state-management

Клиентское состояние на Zustand — слайсы, селекторы, персист, экшены; граница «что НЕ поднимать в глобальный стор». Use при проектировании или правке клиентских сторов состояния во фронтенде.

SKILL.md

GitHub

Навык: State management (Zustand)

Клиентское UI-состояние на Zustand. Серверные данные сюда не кладём — для них TanStack Query (скилл data-fetching).

Что держать в сторе

  • Только клиентское UI-состояние: модалки, выбранные вкладки, черновики форм, тема, флаги.
  • Не держи серверные данные (списки из API), производное состояние (вычисляй селектором) и то, что живёт локально в компоненте.
  • Не храни переведённые строки — держи ключи/текущую локаль, а текст резолвь через слой перевода при рендере (скилл i18n).

Структура

  • Стор на фичу (src/features/<feature>/stores), а не один глобальный god-store.
  • Слайсы: разбивай большой стор на слайсы-функции (set, get) => ({...}) и объединяй.
  • Экшены — внутри стора (методы, вызывающие set), а не разбросаны по компонентам.

Селекторы и перфоманс

  • Подписывайся узко: useStore(s => s.value), а не на весь стор — меньше перерендеров.
  • Для выборки нескольких полей — useShallow (shallow-сравнение), чтобы не ловить лишние ререндеры.

Персист и middleware

  • persist — для сохранения (localStorage), с partialize (что именно сохранять) и version/migrate.
  • devtools — для отладки; immer — для удобных иммутабельных обновлений вложенных структур.

Пример

export const useCartStore = create<CartState>()(
  persist(
    (set) => ({
      items: [],
      add: (item) => set((s) => ({ items: [...s.items, item] })),
      clear: () => set({ items: [] }),
    }),
    { name: "cart", partialize: (s) => ({ items: s.items }) },
  ),
);