State Management
Redux Toolkit: slices и Immer
В чистом Redux добавление одной возможности в корзину это четыре файла: константа типа action, функция-создатель action, ветка в редьюсере со спред-операторами и подключение редьюсера в combineReducers. Половина кода это иммутабельность через многоэтажные спреды для вложенных объектов. Redux Toolkit убирает почти всё это. Одно описание slice генерирует и типы action, и их создатели, и редьюсер, а внутри редьюсера состояние можно менять так, будто его разрешено мутировать. За корректную иммутабельность под капотом отвечает Immer.
- Команды, мигрировавшие с ручного Redux на RTK ради сокращения кода в несколько раз без смены архитектуры
- Корзина и каталог, где вложенные обновления раньше требовали глубоких спредов, а теперь пишутся как прямое присваивание
- Стартовые шаблоны Redux: официальный генератор приложений ставит именно RTK, а не голый Redux
- Приложения, где важна и предсказуемость Redux, и скорость разработки без boilerplate
- Проекты, которым нужны devtools и строгий поток, но без четырёх файлов на каждое действие
Предварительные знания
- Ядро Redux: store, action, reducer, dispatch и однонаправленный поток
- Три принципа Redux, особенно иммутабельность и чистота редьюсеров
- Ручное иммутабельное обновление через спред-операторы и его многословность
Как RTK стал официальным Redux
К 2018 году у Redux была репутация многословного: на простое действие уходило несколько файлов, и команды жаловались на boilerplate. Марк Эриксон и команда Redux ответили выпуском Redux Toolkit (первое имя redux-starter-kit) в 2019 году. RTK собрал лучшие практики в готовый набор: configureStore с разумными настройками по умолчанию, createSlice для генерации action и reducer, встроенный Immer для мутирующего синтаксиса и встроенный reselect. С тех пор официальная документация Redux прямо рекомендует RTK как стандартный способ писать Redux, а голый createStore считается устаревшим подходом. На 2026 год говорить Redux на практике почти всегда означает Redux Toolkit.
createSlice: одно описание вместо четырёх файлов
createSlice принимает имя slice, начальное состояние и набор редьюсеров. Из этого он сам собирает три вещи: тип каждого action в виде имя/действие, создателей action под каждый редьюсер и общий reducer этого slice. Разработчик описывает только то, как меняется состояние, а имена action и их создатели появляются автоматически.
Из этого описания createSlice сгенерировал создателей increment и addBy и присвоил им типы action counter/increment и counter/addBy по шаблону имяСлайса/имяРедьюсера. Тип полезной нагрузки задаётся через PayloadAction, и payload автоматически типизирован. То, что в чистом Redux занимало константы, создателей и switch, здесь умещается в один объект reducers.
configureStore это не просто createStore покороче. Он сам подключает Redux DevTools, добавляет проверки на случайные мутации и несериализуемые значения в dev-режиме и настраивает middleware. Типы RootState и AppDispatch выводятся из самого store, поэтому состояние и dispatch остаются строго типизированными без ручных деклараций.
Что createSlice генерирует из переданного объекта reducers?
Мутирующий синтаксис поверх Immer
Самое заметное в редьюсерах createSlice то, что state можно менять напрямую: state.value += 1 или state.items.push(item). В чистом Redux это нарушало бы принцип иммутабельности. В RTK это безопасно, потому что редьюсеры выполняются внутри Immer. Immer оборачивает состояние в специальный объект-черновик, перехватывает все присваивания и на выходе строит новый иммутабельный объект, оставляя исходный нетронутым.
Слева код выражает намерение напрямую: найти элемент и поставить ему новое количество. Справа то же самое требует трёх уровней спредов и map, чтобы не мутировать вложенные объекты. Immer убирает эту рутину, не отступая от иммутабельности: исходное состояние не меняется, наружу выдаётся новый объект, а ссылки на неизменившиеся ветки переиспользуются.
Понимать, что под мутирующим синтаксисом всё равно лежит иммутабельность, важно по двум причинам. Во-первых, сравнение состояния по ссылке продолжает работать, что и нужно для оптимизаций и devtools. Во-вторых, мутировать можно только сам draft внутри редьюсера, а не внешние объекты: правило прежнее, удобство новое.
Как RTK позволяет писать state.value += 1 в редьюсере, не нарушая иммутабельность Redux?
Правила работы с Immer-редьюсером
У мутирующего синтаксиса Immer есть одно ключевое правило: в редьюсере допустимо либо мутировать черновик, либо вернуть новое значение, но не делать и то и другое сразу. Если код меняет state через присваивания, возвращать ничего не нужно. Если же редьюсер целиком собирает новый объект через return, то мутаций черновика в нём быть не должно.
Ещё одна частая ошибка это попытка заменить состояние целиком присваиванием самой переменной: state = newValue внутри редьюсера. Так не работает, потому что переприсваивание локальной переменной не меняет черновик. Для полной замены состояния используют return нового объекта, а для точечных изменений мутируют поля черновика.
| Намерение | Как делать | Чего избегать |
|---|---|---|
| Изменить часть состояния | Мутировать поля: state.value += 1 | Возвращать значение в том же редьюсере |
| Заменить состояние целиком | return нового объекта | Присваивать state = newValue |
| Сбросить вложенный объект | state.cart = initialCart | Смешивать мутацию и return |
Immer обрабатывает обычные объекты и массивы, а также Map и Set при включении соответствующего плагина. Для большинства Redux-состояний этого достаточно: дерево из объектов, массивов и примитивов. Сложные классы и неклонируемые значения в состоянии хранить не стоит, и это совпадает с требованием Redux держать состояние сериализуемым.
Какое сочетание в одном Immer-редьюсере приведёт к ошибке?
Почему RTK это официальный современный Redux
Redux Toolkit это не отдельная библиотека-конкурент, а официальная надстройка над тем же ядром Redux. Он сохраняет store, action, reducer, dispatch и три принципа без изменений. Меняется только способ записи: вместо ручных констант, создателей и switch-редьюсеров со спредами всё описывается через createSlice и configureStore. Документация Redux прямо называет RTK стандартным способом писать Redux, а голый createStore помечен как устаревший подход.
- Голый Redux — Константы типов, создатели action, switch-редьюсеры, ручные спреды для иммутабельности, ручная настройка devtools и middleware. Много файлов на одно действие
- Redux Toolkit — createSlice генерирует action и reducer, Immer берёт иммутабельность, configureStore включает devtools и проверки по умолчанию. То же ядро, в разы меньше кода
Практический вывод на 2026 год: новый Redux-код пишут на RTK. Голый createStore остаётся в старых проектах и в учебных целях, чтобы видеть устройство ядра, но в новой разработке его не выбирают. При этом RTK не отменяет понимания ядра: знать, что под slice лежат всё те же action и reducer, нужно, чтобы читать devtools, отлаживать и правильно подключать асинхронность и селекторы.
RTK включает в себя и более крупные части экосистемы: createAsyncThunk для асинхронности, createEntityAdapter для нормализации, встроенный reselect для селекторов и RTK Query для серверного состояния. Это не плагины со стороны, а части одного официального пакета, и каждая из них тема отдельного урока этого модуля.
Как соотносятся Redux Toolkit и ядро Redux на 2026 год?
Связь с другими темами
Slice это центральная единица RTK, к которой подключается всё остальное:
- Redux: ядро — RTK не заменяет ядро, а оборачивает его: createSlice генерирует ровно те action и reducer, что разбирались в ядре
- Async через createAsyncThunk — Асинхронные действия подключаются к slice через extraReducers, реагируя на pending/fulfilled/rejected
- Селекторы и reselect — Селекторы читают состояние, которое формирует slice, и мемоизируют производные значения
Итог
- createSlice из одного описания генерирует типы action, их создатели и редьюсер, убирая ручной boilerplate
- configureStore собирает store с разумными настройками по умолчанию: подключённые devtools, Immer и проверки
- Внутри редьюсера slice состояние можно менять в мутирующем стиле, а Immer под капотом создаёт корректное новое состояние
- Immer работает через черновик (draft): мутации применяются к нему, а на выходе получается новый иммутабельный объект
- Три принципа Redux сохраняются: внизу всё та же иммутабельность, RTK лишь прячет её рутину
- Redux Toolkit это официальный современный способ писать Redux, голый createStore считается устаревшим
Связанные уроки
- sm-11-redux-core — RTK это обёртка над ядром Redux: чтобы понять, что генерирует createSlice, нужно знать action, reducer, store
- sm-13-rtk-async-thunks — Поверх slice строится асинхронность через createAsyncThunk: extraReducers подключаются к тому же slice
- sm-14-rtk-selectors — Селекторы и reselect читают состояние, которое формируют slice. Следующий слой над тем же store