Redux Saga 热重载

Redux Saga hot reloading

我正在做一个 React & Redux 项目。项目以前使用webpack-dev-middleware和hot中间件热重载

我在项目中添加了Redux Saga之后,在redux store中添加了saga中间件。似乎每当我更改 saga 代码时,热重载都会中断并显示一条错误消息:

Provider> does not support changing store on the fly. It is most likely that you see this error because you updated to Redux 2.x and React Redux 2.x which no longer hot reload reducers automatically. See https://github.com/reactjs/react-redux/releases/tag/v2.0.0 for the migration instructions.

我知道 Saga 使用生成器并且它是依赖于时间的。是否可以使用 Sagas 热重载页面?就像 Redux reducers 在热重载期间如何自我替换一样。

谢谢!

我正在使用 redux 和 redux-saga 开发一个项目(但不是 React)。我使用 sagaMiddleware.run() 实现了 sagas 的热重载,但您必须按照您提供的 link (https://github.com/reactjs/react-redux/releases/tag/v2.0.0) 中的指示处理模块重新加载并替换 reducers 和 sagas。

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() 函数。它 returns 一个新创建的 sagas 生成器对象的数组,你不能在数组中包含一些已经 运行 sagas 的预先创建的对象。如果你买这个阵列 只有在一个模块中,你可以直接使用常量数组,但是如果你构建它 从不同的模块组成 sagas 你必须确保重新创建 sagas 来自所有模块,所以更好的方法是所有模块都导出创建函数,而不是导出固定的 saga 或 sagas 数组。 例如它可以是这样的函数:

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

显然所有的 sagas 都会从头开始重新开始,如果你有一个复杂的 sagas 使用内部状态,您将失去当前状态。

一种非常相似的方法是使用动态 saga 代替调用 sagaMidleware.run(),这是一种非常相似的解决方案,但您可以重新加载 sagas 的子集并以不同的方式处理它们。有关详细信息,请参阅 https://gist.github.com/mpolci/f44635dc761955730f8479b271151cf2

更新 redux-saga 版本 1.0.0 和更高版本的包:

使用@mpolci 解决方案,只需更改

sagaTask.done.then(() => {

sagaTask.toPromise().then(() => {

一切都开始正常工作。

请参阅 Task 文档