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, особенно иммутабельность и чистота редьюсеров
  • Ручное иммутабельное обновление через спред-операторы и его многословность
  • 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
Redux Toolkit: slices и Immer

0

1

Войти