Почему редюсеры Redux должны быть чистыми функциями
Что проверяют
Понимаете ли вы, как Redux отслеживает изменения, и что чистота редюсера это не идеология, а условие, без которого ломается перерисовка и инструменты отладки.
Как отвечать
Редюсер это функция (state, action) => newState: тот же вход даёт тот же выход, без запросов, таймеров, Math.random(), Date.now() и без правки аргументов на месте.
Причины называйте практические:
- подписчики сравнивают срезы состояния по ссылке. Если сделать
state.items.push(x)и вернуть тот же объект, ссылка не изменилась, и компонент не перерисуется. Баг выглядит как «в сторе всё есть, а на экране пусто»; - воспроизводимость: журнал действий плюс начальное состояние однозначно дают текущее. На этом держатся перемотка в devtools, повтор бага по логу и горячая перезагрузка редюсеров;
- тестируемость: подали состояние и действие, сравнили результат, окружение не нужно.
Побочные эффекты выносятся наружу: запросы в middleware, а генерация идентификатора и отметки времени в функцию подготовки действия, чтобы при повторе журнала значения не менялись.
Обязательно скажите про Redux Toolkit: внутри createSlice мутирующий синтаксис разрешён, state.items.push(x) там законен, потому что Immer подставляет черновик и собирает новый объект сам. Это не отмена правила, а другой способ его выполнить.
Где спотыкаются
Копируют верхний уровень, а вложенный объект правят на месте. Оператор расширения меняет ссылку только на корень, и селектор, который смотрит на вложенный срез, изменения не увидит. Копировать надо всю ветку до изменяемого узла.
Впадают в обратную крайность и возвращают новый объект в каждой ветке, включая ветку по умолчанию. Тогда ссылка меняется на любое действие, мемоизация селекторов обесценивается и перерисовывается всё приложение. На неизвестное действие надо вернуть тот же state.
Ставят Date.now() или генератор идентификаторов внутрь редюсера. Функция перестаёт быть чистой, перемотка в devtools даёт другое состояние, а тест приходится подпирать подменой таймера вместо простого сравнения объектов.