Архитектурные подходы к организации состояния

В Preact состояние компонентов играет ключевую роль в построении динамических интерфейсов. В отличие от традиционных подходов, где управление состоянием часто распределено по DOM-элементам, Preact предлагает функциональные методы работы с состоянием, позволяя строить масштабируемые и предсказуемые приложения.

Локальное состояние компонентов

Локальное состояние создаётся с помощью хука 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>
  );
}

Особенности локального состояния:

  • Обновление состояния вызывает повторный рендер компонента.
  • Доступно только внутри компонента, где оно создано.
  • Простое использование для мелких и изолированных частей интерфейса.

Глобальное состояние через контекст

Для управления состоянием, которое должно быть доступно нескольким компонентам, применяется контекст (createContext). Он позволяет централизованно хранить данные и предоставлять их любому компоненту в дереве.

import { h } from 'preact';
import { createContext } from 'preact';
import { useContext, useState } from 'preact/hooks';

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light');

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedButton() {
  const { theme, setTheme } = useContext(ThemeContext);
  return (
    <button
      style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}
      onCl ick={() => setTheme(theme === 'light' ? 'dark' : 'light')}
    >
      Переключить тему
    </button>
  );
}

Преимущества контекста:

  • Централизованное управление данными.
  • Поддержка масштабируемых приложений без передачи пропсов через несколько уровней.
  • Возможность сочетать с локальным состоянием для отдельных компонентов.

Управление сложным состоянием с useReducer

Для компонентов с большим количеством логики изменения состояния применяется useReducer. Он позволяет описывать все возможные действия через редьюсер, что делает логику более предсказуемой и тестируемой.

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

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>Счётчик: {state.count}</p>
      <button onCl ick={() => dispatch({ type: 'increment' })}>Увеличить</button>
      <button onCl ick={() => dispatch({ type: 'decrement' })}>Уменьшить</button>
    </div>
  );
}

Преимущества useReducer:

  • Чёткое разграничение действий и изменений состояния.
  • Упрощение тестирования бизнес-логики.
  • Удобно для сложных форм и многошаговых процессов.

Внешние менеджеры состояния

Для больших приложений Preact может интегрироваться с внешними менеджерами состояния, такими как Redux или Zustand. Они предоставляют мощные механизмы для управления состоянием через глобальные хранилища, middleware и подписки.

Ключевые аспекты внешних менеджеров:

  • Централизация состояния и унификация работы с данными.
  • Возможность масштабирования крупных приложений.
  • Лёгкая интеграция с отладочными инструментами и middleware.

Смешанные подходы

В реальных проектах часто применяется комбинация локального, контекстного и внешнего состояния. Локальное состояние отвечает за быстрые изменения UI, контекст — за разделяемые настройки и параметры, внешние хранилища — за глобальные данные и синхронизацию с сервером.

Принципы комбинированного подхода:

  • Минимизировать глобальное состояние, оставляя локальные изменения компонентам.
  • Использовать контекст только там, где требуется разделяемое состояние.
  • Выделять редьюсеры для сложной логики и крупных действий.

Рекомендации по организации состояния

  1. Простота первично. Локальное состояние предпочтительно там, где данные не должны покидать компонент.
  2. Контекст для разделяемого состояния. Использовать createContext только для данных, которые реально нужны в нескольких компонентах.
  3. Редьюсер для сложных процессов. Когда логика изменения состояния становится громоздкой или многошаговой, стоит использовать useReducer.
  4. Глобальные менеджеры для больших приложений. Redux, Zustand или другие библиотеки эффективны при необходимости масштабирования и синхронизации данных.

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