Основные альтернативы Redux для управления состоянием:
// Пример с Context API + useReducer
const initialState = { count: 0 };
const reducer = (state, action) => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
};
// Использование
const [state, dispatch] = useReducer(reducer, initialState);
dispatch({ type: 'increment' });Redux долгое время был стандартом для управления состоянием в React-приложениях, но сегодня существует множество альтернатив, которые могут быть проще, легче или лучше подходить для конкретных задач. 🔄
Встроенное в React решение, которое подходит для небольших и средних приложений:
// Создание контекста
const CounterContext = createContext();
// Провайдер с useReducer
function CounterProvider({ children }) {
const [state, dispatch] = useReducer(
(state, action) => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
default: return state;
}
},
{ count: 0 }
);
return (
<CounterContext.Provider value={{ state, dispatch }}>
{children}
</CounterContext.Provider>
);
}
// Использование в компоненте
function Counter() {
const { state, dispatch } = useContext(CounterContext);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</>
);
}Преимущества:
Недостатки:
Библиотека, использующая наблюдаемые объекты и реакции:
// Определение состояния
import { makeObservable, observable, action } from 'mobx';
import { observer } from 'mobx-react-lite';
class CounterStore {
count = 0;
constructor() {
makeObservable(this, {
count: observable,
increment: action,
decrement: action
});
}
increment = () => {
this.count++;
}
decrement = () => {
this.count--;
}
}
const counterStore = new CounterStore();
// Компонент с наблюдением
const Counter = observer(() => {
return (
<>
Count: {counterStore.count}
<button onClick={counterStore.increment}>+</button>
<button onClick={counterStore.decrement}>-</button>
</>
);
});Преимущества:
Недостатки:
Минималистичная библиотека с простым API на хуках:
import create from 'zustand';
// Создание хранилища
const useCounterStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 }))
}));
// Использование в компоненте
function Counter() {
const { count, increment, decrement } = useCounterStore();
return (
<>
Count: {count}
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</>
);
}Преимущества:
Недостатки:
Экспериментальная библиотека от Facebook для атомарного управления состоянием:
import { atom, useRecoilState } from 'recoil';
// Определение атома
const countAtom = atom({
key: 'countState',
default: 0
});
// Использование в компоненте
function Counter() {
const [count, setCount] = useRecoilState(countAtom);
return (
<>
Count: {count}
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</>
);
}
// Оборачиваем приложение в RecoilRoot
function App() {
return (
<RecoilRoot>
<Counter />
</RecoilRoot>
);
}Преимущества:
Недостатки:
Примитивная атомарная библиотека, вдохновленная Recoil:
import { atom, useAtom } from 'jotai';
// Создание атома
const countAtom = atom(0);
// Производные атомы
const doubleCountAtom = atom(
(get) => get(countAtom) * 2
);
// Использование в компоненте
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubleCount] = useAtom(doubleCountAtom);
return (
<>
Count: {count} (Double: {doubleCount})
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</>
);
}Преимущества:
Недостатки:
Библиотека для управления состоянием на основе конечных автоматов:
import { createMachine, assign } from 'xstate';
import { useMachine } from '@xstate/react';
// Определение машины состояний
const counterMachine = createMachine({
id: 'counter',
initial: 'active',
context: { count: 0 },
states: {
active: {
on: {
INCREMENT: {
actions: assign({ count: (ctx) => ctx.count + 1 })
},
DECREMENT: {
actions: assign({ count: (ctx) => ctx.count - 1 })
}
}
}
}
});
// Использование в компоненте
function Counter() {
const [state, send] = useMachine(counterMachine);
return (
<>
Count: {state.context.count}
<button onClick={() => send('INCREMENT')}>+</button>
<button onClick={() => send('DECREMENT')}>-</button>
</>
);
}Преимущества:
Недостатки:
Прокси-ориентированная библиотека для управления состоянием:
import { proxy, useSnapshot } from 'valtio';
// Создание прокси-состояния
const state = proxy({ count: 0 });
// Мутации состояния
const actions = {
increment: () => { state.count++ },
decrement: () => { state.count-- }
};
// Использование в компоненте
function Counter() {
const snap = useSnapshot(state);
return (
<>
Count: {snap.count}
<button onClick={actions.increment}>+</button>
<button onClick={actions.decrement}>-</button>
</>
);
}Преимущества:
Недостатки:
Специализированная библиотека для управления серверным состоянием:
import { useQuery, useMutation, QueryClient, QueryClientProvider } from 'react-query';
// Настройка клиента
const queryClient = new QueryClient();
// Компонент с запросами
function TodoList() {
// Получение данных
const { data: todos } = useQuery('todos', fetchTodos);
// Мутация данных
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries('todos');
}
});
return (
<>
<ul>
{todos?.map(todo => <li key={todo.id}>{todo.title}</li>)}
</ul>
<button onClick={() => mutation.mutate({ title: 'New Todo' })}>
Add Todo
</button>
</>
);
}
// Оборачиваем приложение
function App() {
return (
<QueryClientProvider client={queryClient}>
<TodoList />
</QueryClientProvider>
);
}Преимущества:
Недостатки:
| Библиотека | Размер | Сложность | Производительность | Экосистема |
|---|---|---|---|---|
| Redux | Средний | Высокая | Хорошая | Обширная |
| Context | 0KB | Низкая | Средняя | Встроенная |
| MobX | Малый | Средняя | Отличная | Хорошая |
| Zustand | Малый | Низкая | Хорошая | Растущая |
| Recoil | Средний | Средняя | Хорошая | Растущая |
| Jotai | Малый | Низкая | Хорошая | Новая |
| XState | Средний | Высокая | Хорошая | Растущая |
| Valtio | Малый | Низкая | Отличная | Новая |
| React Query | Средний | Средняя | Отличная | Хорошая |
Современные альтернативы Redux предлагают более простые и специализированные решения для управления состоянием:
Выбор зависит от размера проекта, требований к производительности и предпочтений команды. 🎯