Прощай, шаблонный код Redux? Подробно о лёгком менеджере состояния Zustand
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 определённо заслуживает внимания.