Инициализация и обновление состояния

Состояние (state) в Preact играет ключевую роль в построении динамических интерфейсов. Оно позволяет компонентам хранить данные, изменяемые во времени, и автоматически перерисовывать интерфейс при изменении этих данных. Preact использует облегчённую модель реактивности, близкую к React, но с минимальным весом и высокой производительностью.


Создание состояния с помощью useState

В функциональных компонентах состояние создаётся с помощью хука useState. Синтаксис:

import { h } from 'preact';
import { useState } from 'preact/hooks';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Текущее значение: {count}</p>
      <button onCl ick={() => setCount(count + 1)}>Увеличить</button>
    </div>
  );
}

Разбор ключевых моментов:

  • useState(0) — инициализирует состояние значением 0.
  • count — текущий вариант состояния.
  • setCount — функция для обновления состояния. Любое её использование вызывает повторный рендер компонента с новым значением.

useState можно использовать несколько раз в одном компоненте для хранения разных данных:

const [name, setName] = useState('');
const [age, setAge] = useState(25);

Ленивое инициализирование состояния

Если начальное состояние вычисляется дорогостоящей функцией, Preact позволяет передавать функцию в useState. Эта функция будет выполнена один раз при монтировании компонента:

const [data, setData] = useState(() => fetchInitialData());

Это предотвращает лишние вычисления при каждом рендере.


Обновление состояния на основе предыдущего значения

При изменении состояния, зависящего от предыдущего значения, рекомендуется использовать коллбек-форму:

setCount(prevCount => prevCount + 1);

Такой подход гарантирует корректное обновление при множественных вызовах setCount, особенно в асинхронных сценариях.


Множественные состояния и их структура

Для сложных данных можно использовать один объект состояния, но тогда важно правильно обновлять отдельные поля:

const [form, setForm] = useState({ username: '', password: '' });

function updateUsername(newUsername) {
  setForm(prevForm => ({ ...prevForm, username: newUsername }));
}

Использование спред-оператора ...prevForm сохраняет неизменные поля объекта.


Особенности ререндеринга при изменении состояния

  • Preact сравнивает новое и старое состояние по ссылке. Если ссылка изменилась, компонент перерисовывается.
  • Мутирование объекта состояния без изменения ссылки не вызовет ререндер. Поэтому всегда следует создавать новый объект или массив при обновлении.
// Некорректно
form.username = 'newName';
setForm(form); // Компонент не перерисуется

// Корректно
setForm({ ...form, username: 'newName' });

Управление состоянием в классовых компонентах

В Preact также поддерживаются классовые компоненты:

import { h, Component } from 'preact';

class Counter extends Component {
  constructor() {
    super();
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Текущее значение: {this.state.count}</p>
        <button onCl ick={this.increment}>Увеличить</button>
      </div>
    );
  }
}

Особенности:

  • Состояние хранится в this.state.
  • Обновление происходит через this.setState().
  • Частичные обновления объекта состояния объединяются автоматически (shallow merge).

Синхронизация состояния с эффектами

Иногда требуется реагировать на изменение состояния через побочные эффекты. Для этого используется useEffect:

import { useEffect } from 'preact/hooks';

useEffect(() => {
  console.log('Счётчик обновлён:', count);
}, [count]);
  • Зависимость [count] гарантирует, что эффект будет вызван только при изменении count.
  • Без зависимостей эффект выполняется после каждого рендера.
  • Пустой массив [] вызывает эффект только при монтировании компонента.

Советы по оптимизации

  • Разделение состояния на несколько хуков useState может повысить производительность, так как изменение одного состояния не триггерит ререндер других.
  • Для массивов и объектов рекомендуется создавать новые копии при обновлении, чтобы избежать ошибок с ререндером.
  • Использование функций для вычисления начального состояния предотвращает ненужные перерасчёты.

Система состояния в Preact обеспечивает компактный и гибкий инструмент для управления данными компонентов, обеспечивая высокую производительность и предсказуемое поведение интерфейса. Правильное использование хуков useState, коллбеков для обновления и методов классовых компонентов позволяет строить динамичные и отзывчивые приложения с минимальной сложностью.