Zustand и легковесные решения

Основы управления состоянием

Preact, как минималистичная альтернатива React, предоставляет базовые средства управления состоянием через хуки useState и useReducer. Однако при увеличении сложности приложения становится необходим более структурированный подход для глобального состояния. Для таких случаев отлично подходят легковесные библиотеки, одна из которых — Zustand. Она сочетает простоту, производительность и компактность API.

Архитектура Zustand

Zustand реализует принцип хранения состояния в виде централизованного стора, к которому компоненты могут подписываться. Состояние в сторе является реактивным, что позволяет обновлять только те компоненты, которые используют изменённые данные. Основные элементы архитектуры:

  • Store — объект состояния, содержащий данные и методы их изменения.
  • Actions — функции, которые изменяют состояние, аналогичные редьюсерам.
  • Selectors — функции для выборки конкретных данных из стора.

Пример создания простого стора:

import create from 'zustand';

const useStore = create((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
  decrement: () => set((state) => ({ count: state.count - 1 })),
}));

Здесь useStore — это кастомный хук, который позволяет компонентам подписываться на состояние. Любое изменение через increment или decrement автоматически приведёт к рендеру компонентов, использующих count.

Интеграция с Preact

Zustand полностью совместим с Preact, так как использует стандартные хуки React API. Для Preact следует убедиться, что проект использует preact/compat, если требуется интеграция с библиотеками, изначально рассчитанными на React.

Пример использования стора в Preact-компоненте:

import { h } from 'preact';
import { useStore } from './store';

function Counter() {
  const count = useStore((state) => state.count);
  const increment = useStore((state) => state.increment);
  const decrement = useStore((state) => state.decrement);

  return (
    <div>
      <h1>{count}</h1>
      <button onCl ick={increment}>+</button>
      <button onCl ick={decrement}>-</button>
    </div>
  );
}

Использование селекторов (state) => state.count позволяет компоненту подписываться только на нужную часть состояния, минимизируя лишние ререндеры.

Преимущества легковесного подхода

Zustand выгодно отличается по нескольким параметрам:

  1. Малый размер — библиотека занимает около 1 КБ после минификации и gzip.
  2. Простота API — нет сложных boilerplate, как в Redux.
  3. Поддержка реактивности — подписка на конкретные поля состояния.
  4. Совместимость с серверным рендерингом — можно использовать в Preact SSR.

Продвинутые техники

  1. Композиция стора — создание нескольких стора для разных областей состояния:
const useUserStore = create((set) => ({
  user: null,
  setUser: (user) => set({ user }),
}));

const useThemeStore = create((set) => ({
  theme: 'light',
  toggleTheme: () => set((state) => ({ theme: state.theme === 'light' ? 'dark' : 'light' })),
}));
  1. Middleware — добавление логирования или сохранения состояния в localStorage:
import { devtools, persist } from 'zustand/middleware';

const useStore = create(
  devtools(
    persist(
      (set) => ({
        count: 0,
        increment: () => set((state) => ({ count: state.count + 1 })),
      }),
      { name: 'counter-storage' }
    )
  )
);
  1. Производительность — минимальные перерендеры благодаря выборочным подпискам и селекторам.

Сравнение с другими легковесными решениями

  • Jotai — атомарный подход, подходит для сложных состояний с множеством зависимостей.
  • Valtio — прокси-состояние, обеспечивает прозрачную реактивность, напоминает MobX.
  • Zustand — более декларативный, простой в освоении и хорошо интегрируется с Preact.

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

Практические рекомендации

  • Разделять состояние на логические модули с отдельными сторами.
  • Использовать селекторы для минимизации перерендеров.
  • Применять middleware для кэширования или отладки.
  • Избегать хранения больших структур данных, изменяемых часто; лучше разбивать их на мелкие части.

Использование Zustand позволяет поддерживать Preact-приложение компактным, быстрым и легко расширяемым без перегрузки архитектуры сложными инструментами.