Редукторы не должны отвечать за управление асинхронными c действиями. setInterval не изменяет глобальное состояние по своей сути, но если оно вызывается изнутри редуктора, оно имеет потенциал для доступа и изменения состояния через ссылки на объекты.
Цель этого правила - сохранить ваш код чистым, сфокусированным и просто. Как таковые редукторы должны принимать состояние и действие и генерировать новое состояние синхронно. Никаких других махинаций.
Вот почему существуют Redux Thunk и Redux Sagas. Они дают нам возможность обрабатывать многие фазы асинхронных действий c, сохраняя логику c вне редукторов.
Например, представьте следующий редуктор:
// Simple reducer that ignores action and just adds 1 to
// state count every time
function myReducer(state, action) {
return {
count: state.count + 1
};
}
// Reducer that calls setInterval
function myBadReducer(state, action) {
// When our reducer gets called we create an interval
// that increases count directly by 1 every 2 seconds
// BTW This is exceptionally bad since it creates a duplicate
// interval everytime the reducer is invoked.
setInterval(() => {
state.count += 1;
}, 2000);
return state;
}
Плохой редуктор изменяет состояние напрямую через ссылки, которые нарушают созданный для нас редукционный поток. Состояние -> Действие -> Редуктор -> Новое состояние. Это делает невозможным для Redux оперативное уведомление всех подписчиков о том, что состояние изменилось, поскольку он не отслеживает каждый адрес памяти.
Вместо этого вам следует настроить отдельный процесс вне редуктора (или использовать Redux Sagas), который вызывает действовать по мере необходимости (с интервалом или как-то иначе), и пусть хранилище обрабатывает вызов редуктора и каждый раз генерирует новое состояние.