Redux Toolkit и альтернативы: что выбрать и почему
Вопрос про выбор инструмента: интервьюеру важен не список библиотек, а критерии решения.
Redux Toolkit (RTK) — официальный набор поверх Redux: срезы состояния через createSlice, встроенный Immer, настроенный store и типизация из коробки.
Вопрос
«Какой state manager используете и почему? Что даёт Redux Toolkit по сравнению с классическим Redux? Какие есть альтернативы?»
Что на самом деле проверяет интервьюер
Умение обосновывать. Ответ «Redux, потому что стандарт» слаб так же, как «Redux устарел, все на Zustand». Ждут понимания, за какие свойства платят сложностью.
Развёрнутый ответ
Что RTK убрал из классического Redux
- Ручные константы типов экшенов и switch в редьюсерах — теперь
createSliceгенерирует и то, и другое. - Ручное копирование объектов — внутри работает Immer.
- Настройку store и middleware —
configureStoreсразу подключает thunk и dev-проверки. - Отдельную типизацию — типы выводятся из срезов.
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
export const fetchCart = createAsyncThunk('cart/fetch', async (userId: string) => {
const res = await fetch(`/api/cart/${userId}`);
return res.json();
});
const cartSlice = createSlice({
name: 'cart',
initialState: { items: [] as Item[], status: 'idle' as Status },
reducers: {
// выглядит как мутация, но Immer превращает это в новый объект
add(state, action) {
state.items.push(action.payload);
},
remove(state, action) {
state.items = state.items.filter((i) => i.id !== action.payload);
},
},
extraReducers: (builder) => {
builder
.addCase(fetchCart.pending, (state) => { state.status = 'loading'; })
.addCase(fetchCart.fulfilled, (state, action) => {
state.status = 'ready';
state.items = action.payload;
});
},
});
export const { add, remove } = cartSlice.actions;
export default cartSlice.reducer;
Селекторы и лишние рендеры
// ПЛОХО: новый массив на каждом вызове — компонент рендерится на любое изменение store
const visible = useSelector((s) => s.cart.items.filter((i) => !i.hidden));
// ХОРОШО: мемоизированный селектор
import { createSelector } from '@reduxjs/toolkit';
const selectVisibleItems = createSelector(
(s) => s.cart.items,
(items) => items.filter((i) => !i.hidden)
);
const visible = useSelector(selectVisibleItems);
Это один из самых частых практических вопросов: useSelector сравнивает результат строгим равенством, поэтому селектор обязан возвращать стабильную ссылку.
Альтернативы — обзорно
| Инструмент | Модель | Когда уместен |
| Redux Toolkit | единый store, экшены, редьюсеры | большая команда, строгие соглашения, middleware, отладка |
| Zustand | store как хук, без провайдера | небольшой и средний проект, минимум кода |
| Jotai / Recoil | атомы, состояние снизу вверх | много мелких независимых кусочков состояния |
| MobX | наблюдаемые объекты, автоматические подписки | команда с ООП-опытом, сложные модели предметной области |
| TanStack Query / RTK Query | кэш серверных данных | почти всегда, когда есть API |
// Zustand для сравнения: store без провайдера и без boilerplate
import { create } from 'zustand';
export const useCart = create<CartState>((set) => ({
items: [],
add: (item) => set((s) => ({ items: [...s.items, item] })),
clear: () => set({ items: [] }),
}));
// в компоненте подписываемся точечно, только на нужный срез
const count = useCart((s) => s.items.length);
Особенности мобильного контекста
- Persist. Приложение выгружается системой из памяти, поэтому корзину, черновики и токен обычно сохраняют:
redux-persistповерх AsyncStorage или MMKV. - Оффлайн. Мобильная сеть пропадает постоянно — очередь отложенных действий и оптимистичные обновления обсуждают на собеседовании часто.
- Размер store. Хранить в нём тяжёлые списки и base64-картинки — быстрый путь к нехватке памяти на бюджетных устройствах.
Типичные ошибки кандидатов
- Не могут объяснить, почему в RTK допустима «мутация» — не знают про Immer.
- Пишут селекторы, возвращающие новые массивы, и потом жалуются на тормоза.
- Кладут в глобальный store серверные данные и вручную пишут кэш и инвалидацию.
- Обосновывают выбор модой, а не свойствами проекта: размером команды, сроком жизни кода, требованиями к отладке.
Как ответить кратко
«Redux Toolkit — это Redux без boilerplate: createSlice сам генерирует экшены и редьюсеры, внутри Immer, поэтому редьюсер выглядит как мутация, а на выходе получается новый неизменяемый state; configureStore настраивает middleware и типизацию. Важная деталь — селекторы: useSelector сравнивает результат по ссылке, поэтому производные значения считаю через createSelector. Из альтернатив: Zustand для компактных проектов, Jotai для атомарного состояния, MobX для сложных моделей. Серверные данные в любом случае держу в RTK Query или TanStack Query, а не в общем store. На мобильном добавляю persist и продумываю оффлайн.»