Как изменился Redux и почему его до сих пор ставят в новые проекты
Помните времена, когда простой счётчик на Redux требовал создать три отдельных файла, объявить десяток констант и расписать огромный switch-case в редьюсере? Из-за этого кучи шаблонного кода библиотеку успели возненавидеть тысячи разработчиков. Но Redux давно не тот, каким был в 2015 году.
Разработчики вовремя поняли проблему и выпустили Redux Toolkit (RTK). Сегодня он стал стандартом для работы с библиотекой и убрал почти всё, за что Redux раньше критиковали.
Зачем вообще нужен глобальный стейт-менеджер
В небольших React-приложениях легко обойтись обычной передачей пропсов или встроенным React Context. Проблемы начинаются при разрастании проекта. Когда данные из одной формы должны одновременно обновлять боковую панель, шапку сайта и отправлять аналитику, цепочка пропсов превращается в хаос.
Redux держит состояние приложения в одном объекте (store). Вы не меняете этот объект напрямую. Вместо этого вы отправляете действие (action), а чистые функции, редьюсеры, вычисляют новое состояние на основе старого.
Такой подход дает понятную предсказуемость. Если в приложении что-то сломалось, через Redux DevTools можно посмотреть полную историю изменений стейта и открутить время назад, шаг за шагом отслеживая действия пользователя.
Как Redux Toolkit упростил жизнь
Раньше для обновления одного поля приходилось руками следить за иммутабельностью объекта, создавая громоздкие спреды.
В Redux Toolkit встроен Immer. Теперь код внутри редьюсеров пишется так, будто вы мутируете состояние напрямую, а библиотека сама превратит это в безопасное иммутабельное обновление.
Посмотрим на базовый пример со счётчиком:
import { createSlice, configureStore } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
incremented: state => {
// Immer улавливает "мутацию" и создает новое состояние
state.value += 1
},
decremented: state => {
state.value -= 1
}
}
})
export const { incremented, decremented } = counterSlice.actions
const store = configureStore({
reducer: counterSlice.reducer
})
store.subscribe(() => console.log(store.getState()))
store.dispatch(incremented()) // { value: 1 }
store.dispatch(incremented()) // { value: 2 }
store.dispatch(decremented()) // { value: 1 }
Никаких отдельных файлов с типами экшенов. Функция createSlice сама создала и редьюсер, и генераторы экшенов.
Когда Redux нужен, а когда лучше обойтись без него
Автор библиотеки Дан Абрамов ещё годы назад написал статью «You Might Not Need Redux». Этот совет актуален до сих пор.
Redux пригодится в конкретных ситуациях:
- Данных много, они активно меняются со временем и используются в разных частях приложения.
- Логика обновления состояния сложная или требует строгой последовательности.
- Необходима удобная отладка с прозрачной историей всех событий.
- В команде работает много человек, и нужен единый понятный паттерн работы с данными.
Если у вас простое приложение, где данные нужно передать на пару уровней вниз, тянуть сюда Redux не стоит. Лишние абстракции только усложнят код.
Быстрый старт
Проще всего запустить проект на Vite с готовым шаблоном Redux Toolkit и TypeScript:
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
Для Next.js есть готовый шаблон от Vercel:
npx create-next-app --example with-redux my-app
Если подключаете библиотеку к существующему проекту, достаточно установить два пакета:
npm install @reduxjs/toolkit react-redux
Что в итоге
Ядро Redux весит около 2 Кб. Библиотека давно переросла период бесконечного шаблонного кода. В связке с Redux Toolkit вы получаете строгий и предсказуемый инструмент для управления состоянием, который отлично работает в крупных проектах.