Почему побочные эффекты нельзя делать в редюсерах Redux и где их лучше реализовывать
Что проверяют
Понимаете ли вы, что чистота редюсера это не стилевое требование, а условие, на котором держится вся отладка Redux. Заодно смотрят, знаете ли вы, куда эффекты переехали в современном наборе инструментов.
Как отвечать
Редюсер это функция (state, action) => newState, от которой требуется три вещи: на одних и тех же аргументах возвращать один и тот же результат, не менять аргументы, ничего не делать во внешнем мире. Значит, внутри нет ни запроса к серверу, ни записи в хранилище браузера, ни Date.now() и Math.random(), ни диспатча другого действия.
Причина практическая. Состояние восстанавливается повторным применением тех же действий: на этом стоят перемотка в devtools, воспроизведение сценария по журналу действий, восстановление после перезагрузки. Эффект внутри редюсера при перемотке выполнится заново, а его результат в состоянии не воспроизведётся.
Куда их девать:
- middleware: thunk для «сходить в сеть и диспатчнуть результат», listener middleware для реакции на действие, saga на генераторах для длинных сценариев с отменой;
- слой запросов к серверу, например RTK Query, который сам хранит кэш, статусы и правила инвалидации и снимает большую часть ручного кода загрузки;
- сам компонент, если эффект локальный и в хранилище ему делать нечего.
Где спотыкаются
Считают, что Immer в createSlice разрешил мутации. Меняется черновик, а не состояние, и правило остаётся: либо правите черновик, либо возвращаете новое значение, но не то и другое в одной функции.
Пишут в хранилище браузера прямо из редюсера, «это же просто сохранение». Это такой же эффект: он отработает при каждом повторе действия и сломает перемотку.
Мутируют состояние вне createSlice и потом не могут понять, почему компонент не перерисовался. Ссылка на объект та же, сравнение в селекторе считает состояние прежним, и рендера не будет.