Какие cтэйт-менеджеры использовал кроме Redux?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Моё знакомство с альтернативными стэйт-менеджерами
Помимо Redux, который я активно использовал в проектах на React в течение нескольких лет, я работал с рядом других популярных и современных решений для управления состоянием. Каждый из них я выбирал в зависимости от требований проекта: его масштаба, сложности состояния, потребностей в производительности и предпочтений команды.
1. MobX
MobX стал для меня первым серьёзным опытом с альтернативным подходом, основанным на реактивном программировании и наблюдаемых объектах (observables). Я использовал его в двух крупных SPA-приложениях.
- Ключевые концепции: Вместо иммутабельного состояния и чистых редьюсеров, как в Redux, MobX позволяет работать с изменяемыми данными, используя декораторы (или функции)
@observable,@computedи@action. - Преимущества, которые я оценил: Значительно меньше шаблонного кода (boilerplate) по сравнению с классическим Redux. Состояние обновляется "магически" — компоненты автоматически реагируют на изменения тех наблюдаемых полей, которые они используют. Это делает код более декларативным и простым для понимания.
- Пример использования:
import { makeObservable, observable, action, computed } from "mobx";
import { observer } from "mobx-react-lite";
class TodoStore {
todos = [];
constructor() {
makeObservable(this, {
todos: observable,
addTodo: action,
completedCount: computed,
});
}
addTodo(text) {
this.todos.push({ id: Date.now(), text, completed: false });
}
get completedCount() {
return this.todos.filter(t => t.completed).length;
}
}
const store = new TodoStore();
// Компонент React, обёрнутый в observer, будет перерендериваться только при изменении используемых им observable полей.
const TodoList = observer(({ store }) => (
<div>
<span>Completed: {store.completedCount}</span>
{store.todos.map(todo => <div key={todo.id}>{todo.text}</div>)}
</div>
));
2. Zustand
Zustand — это минималистичная, но мощная библиотека, которую я выбрал для нескольких последних проектов. Она удачно сочетает простоту и гибкость.
- Ключевые концепции: Создание хранилища (store) — это просто вызов функции
create. Состояние — это изменяемый объект, но обновления производятся через иммутабельные функции (похожие наsetStateв React). Библиотека очень легковесна и не требует оборачивания приложения в провайдер (Provider). - Преимущества, которые я оценил: Практически отсутствует boilerplate. Отличная интеграция с React. Встроенная поддержка селекторов и middleware (например, для дебаггинга или persistence). Работать с ним интуитивно понятно, особенно если есть опыт с React-стейтом.
- Пример использования:
import create from 'zustand';
import { persist } from 'zustand/middleware';
const useBearStore = create(persist(
(set, get) => ({
bears:监测0,
increasePopulation: () => set(state => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
// Легко создавать производные состояния (аналогично computed в MobX)
get bearDescription() {
const count = get().bears;
return `There are ${count} bears in the store`;
}
}),
{
name: 'bear-storage', // имя для localStorage
}
));
// Использование в компоненте
function BearCounter() {
const bears = useBearStore(state => state.bears);
const increase = useBearStore(state => state.increasePopulation);
const description = useBearStore(state => state.bearDescription);
return (
<>
<h1>{bears} bears around here</h1>
<p>{description}</p>
<button onClick={increase}>Add one</button>
</>
);
}
3. Context API + useReducer
Для небольших и средних приложений я часто использовал встроенное решение React — комбинацию Context API и хука useReducer. Это не отдельная библиотека, но полноценный стэйт-менеджер.
- Ключевые концепции:
useReducerпредоставляет Redux-MQ схему (стейт, действия, редьюсер) в пределах компонента или контекста.Contextпозволяет передать это состояние вглубь дерева компонентов без пропс-дриллинга. - Преимущества, которые я оценил: Не требует внешних зависимостей. Отлично подходит для логически изолированных частей состояния (например, тема UI, аутентификация, модальные окна). Позволяет избежать излишней сложности, когда глобальное хранилище (как Redux) было бы overkill.
- Пример использования:
import React, { createContext, useReducer, useContext, useMemo } from 'react';
const AuthContext = createContext();
function authReducer(state, action) {
switch (action.type) {
case 'LOGIN':
return { user: action.payload, isAuthenticated: true };
case 'LOGOUT':
return { user: null, isAuthenticated: false };
default:
return state;
}
}
function AuthProvider({ children }) {
const [state, dispatch] = useReducer(authReducer, { user: null, isAuthenticated: false });
// Мемоизация значения контекста для оптимизации
const value = useMemo(() => ({ state, dispatch }), [state]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
function useAuth() {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within an AuthProvider');
}
return context;
}
// В компоненте
function LoginButton() {
const { state, dispatch } = useAuth();
return (
<button onClick={() => dispatch({ type: 'LOGIN', payload: { name: 'John' } })}>
Log in as John
</button>
);
}
4. Recoil (экспериментальный опыт)
Я также изучал Recoil от Facebook (ныне Meta) для одного внутреннего экспериментального проекта. Его ключевые концепции — atoms (мельчайшие части состояния) и selectors (производные состояния). Он предлагает очень React-(хороший) способ управления состоянием, но на момент моего использования был ещё недостаточно зрелым, и его долгосрочная поддержка вызывала вопросы. Поэтому для продакшена я пока предпочитал более стабильные варианты, такие как Zustand или MobX.
Критерии выбора стэйт-менеджера в моей практике
- Масштаб проекта: Для небольших — Context + useReducer, для средних и крупных — Zustand или MobX.
- Сложность состояния: Если много производных данных (computed) — MobX. Если нужна простая централизованная модель — Zustand.
- Производительность: Все современные библиотеки (Zustand, MobX, Recoil) предлагают тонко-настроенную подписку на изменения, что минимизирует перерендеры. Для Redux это требовало ручной оптимизации с
React.memoи селекторами. - Предпочтения команды: Простота освоения (Zustand часто выигрывает) и согласованность с архитектурными принципами проекта.
Таким образом, мой опыт не ограничивается одним инструментом. Понимание сильных и слабых сторон разных подходов позволяет выбирать наиболее эффективное решение для каждой конкретной задачи.