Прощай, шаблонный код Redux? Подробно о лёгком менеджере состояния Zustand

2 мин

1. «Проблемы» Redux

Redux, без сомнения, является самой известной и мощной библиотекой управления состоянием в экосистеме React. Однонаправленный поток данных, отладка с путешествием во времени и другие возможности делают его надёжным выбором для больших и сложных приложений. Однако во многих небольших и средних проектах «шаблонный код» (Boilerplate) Redux часто доставляет немало хлопот:

  • Actions & Action Creators: Необходимо определять множество типов action и функций их создания.
  • Reducers: Приходится писать большие конструкции switch для обработки разных action.
  • Dispatch & Selectors: В компонентах action отправляются через dispatch, а подписка на изменения состояния выполняется через useSelector.
  • Context Provider: Корень приложения необходимо обернуть в <Provider>.

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

2. Zustand — глоток свежего воздуха

Zustand («состояние» по-немецки) — это лёгкая библиотека управления состоянием, разработанная командой Poimandres, создавшей react-three-fiber. Её философия — минимализм и ненавязчивость.

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

  • Очень мало кода: Для реализации одной функции Zustand обычно требует лишь малую долю кода, необходимого Redux.
  • Основан на Hooks: Всё строится вокруг одного пользовательского Hook, что соответствует привычкам современной React-разработки.
  • Не требует Context Provider: Верхний уровень приложения не нужно оборачивать в Provider. Store не зависит от дерева компонентов, поэтому его можно импортировать и использовать где угодно.
  • Легко освоить: API предельно прост, основные приёмы можно изучить за несколько минут.

3. Основы использования

Работа с Zustand делится на два шага: создание Store и его использование в компоненте.

a. Создание Store

Store можно определить в любом файле .js или .ts.

// src/store.js
import { create } from 'zustand';

const useBearStore = create((set) => ({
  bears: 0,
  increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
  removeAllBears: () => set({ bears: 0 }),
}));

export default useBearStore;

Функция create принимает callback, аргументом которого является функция set, похожая на setState в React. Здесь определяются состояние и методы его обновления.

b. Использование в компоненте

Используйте его в любом компоненте как обычный Hook.

// src/components/BearCounter.jsx
import useBearStore from '../store';

function BearCounter() {
  const bears = useBearStore((state) => state.bears);
  return <h1>{bears} around here ...</h1>;
}

Обратите внимание: через функцию-селектор (state) => state.bears мы подписываемся на состояние bears. Это важно, поскольку компонент будет повторно рендериться только при изменении bears, что предотвращает ненужные затраты производительности.

// src/components/Controls.jsx
import useBearStore from '../store';

function Controls() {
  const increasePopulation = useBearStore((state) => state.increasePopulation);
  return <button onClick={increasePopulation}>one up</button>;
}

Получить action так же просто.

4. Асинхронные Action

Zustand также естественно работает с асинхронными операциями. Никакое промежуточное ПО вроде redux-thunk или redux-saga не требуется.

const useAsyncStore = create((set) => ({
  data: null,
  fetchData: async (url) => {
    const response = await fetch(url);
    const data = await response.json();
    set({ data });
  },
}));

Заключение

Zustand не стремится полностью заменить Redux. У Redux по-прежнему есть преимущества в строгих правилах, отслеживаемости и огромной экосистеме.

Однако для подавляющего большинства React-приложений Zustand предлагает более простой и быстрый вариант с меньшей когнитивной нагрузкой. Если вы устали от формальностей Redux или следующему проекту нужен лёгкий и гибкий менеджер состояния, Zustand определённо заслуживает внимания.