Redux Saga горячая перезагрузка

Я работал над проектом React и Redux. В проекте использовалось webpack-dev-middleware и горячее промежуточное ПО для горячей перезагрузки.

После того, как я добавил Redux Saga в проект и добавил промежуточное программное обеспечение саги в магазин redux. Кажется, что всякий раз, когда я меняю коды саги, горячая перезагрузка сломается и отобразит сообщение об ошибке:

Поставщик > не поддерживает изменение store на лету. Скорее всего, вы увидите эту ошибку, потому что вы обновили до Redux 2.x и React Redux 2.x, которые больше не горят перезагружаемыми редукторами. См. https://github.com/reactjs/react-redux/releases/tag/v2.0.0 для инструкций по миграции.

Я понимаю, что Saga использует генераторы и зависит от времени. Возможно ли перезагрузить страницу с помощью Sagas? точно так же, как редукторы Redux заменяют себя во время горячей перезагрузки.

Спасибо!

Ответ 1

Я работаю над проектом с сокращением и сокращением саги (но не реагирую). Я выполнил горячую перезагрузку саг с помощью sagaMiddleware.run(), но вам нужно обработать перезагрузку модуля и заменить редукторы и саги, как указано в предоставленной вами ссылке (https://github.com/reactjs/react-redux/releases/tag/v2.0.0).

import { createStore } from 'redux';
import rootReducer from '../reducers/index';
import getSagas from '../sagas';

export default function configureStore(initialState) {
  const sagaMiddleware = createSagaMiddleware()
  const store = createStore(rootReducer, initialState, applyMiddleware(sagaMiddleware));
  let sagaTask = sagaMiddleware.run(function* () {
     yield getSagas()
  })
  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers/index');
      store.replaceReducer(nextRootReducer);
    });
    module.hot.accept('../sagas', () => {
      const getNewSagas = require('../sagas');
      sagaTask.cancel()
      sagaTask.done.then(() => {
        sagaTask = sagaMiddleware.run(function* replacedSaga (action) {
          yield getNewSagas()
        })
      })
    })
  }

  return store;
}

Важно отметить функцию getSagas(). Он возвращает массив только что созданного объекта-генератора саг, вы не можете иметь некоторый предварительно обработанный объект в массиве из уже запущенных саг. Если вы построите этот массив только в одном модуле вы можете напрямую использовать постоянный массив, но если вы его построите составляя саги из разных модулей, вы должны обязательно воссоздать саги из всех модулей, поэтому лучший способ заключается в том, что все модули экспортируют функцию создания вместо экспорта фиксированной саги или массива саг. Например, это может быть такая функция:

export default () => [
  takeEvery(SOME_ACTION, someActionSaga),
  takeEvery(OTHER_ACTION, otherActionSaga),
]

Очевидно, что все саги перезапускаются с самого начала, и если у вас есть сложные саги с внутренним состоянием вы теряете текущее состояние.

Очень похожий подход заключается в использовании динамической саги вместо вызова sagaMidleware.run(), это очень похожее решение, но вы можете перезагрузить подмножества саг и обрабатывать их по-разному. Для получения дополнительной информации см. https://gist.github.com/mpolci/f44635dc761955730f8479b271151cf2