与 Redux 反应热重载

React Hot Reload with Redux

我已经获得了与 HMR / React Hot Reloader 相关的所有内容,因为它与视图有关。但是在添加 redux、react-redux 等之后......每当我修改视图或 reducer 时,我都会收到以下错误:

<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.

跟随错误中的 link 导致 2 岁 post 关于显式使用 replaceReducer,所以这就是我所做的。

我的版本:

"redux": "^3.7.2" "react-redux": "^5.0.6"

我觉得这主要是因为我不了解 module.hot.accept 呼叫的位置和方式(如果可以有多个?)。相关代码如下。

boot.js(入口点)

import { Provider } from 'react-redux';
import { AppContainer } from 'react-hot-loader';
import { ConnectedRouter } from 'react-router-redux';

import App from './App';

import { configureStore, history } from './store/configureStore';

let store = configureStore();

function renderApp() {
    ReactDOM.render(
      <AppContainer>
        <Provider store={store}>
          <ConnectedRouter history={history}>
            <App />
          </ConnectedRouter>
        </Provider>
      </AppContainer>
      , document.getElementById("app"));
}

renderApp();

if (module.hot) {
    module.hot.accept(() => {
        renderApp();
    })
}

configureStore.js

import createHistory from 'history/createBrowserHistory';
import { createStore, combineReducers, compose, applyMiddleware } from 'redux';
import { routerMiddleware, routerReducer } from 'react-router-redux';
import thunk from 'redux-thunk';

import DevTools from '../components/DevTools';

import * as rootReducer from '../services/rootReducer';

const composeEnhancers = compose;

export const history = createHistory();

const middleware = routerMiddleware(history);

export function configureStore(initialState) {
  const reducers = { ...rootReducer, router: routerReducer };

  const store =  createStore(
    combineReducers(reducers),
    initialState,
    composeEnhancers(
      applyMiddleware(middleware, thunk),
      DevTools.instrument()
    )
  );

  if (module.hot) {
    module.hot.accept('../services/rootReducer', () => {
      const nextRootReducer = require('../services/rootReducer').default;
      const finalReducer = {...nextRootReducer, router: routerReducer };
      store.replaceReducer(finalReducer);
    })
  }

  return store;
}

我的 configureStore 中的 module.hot.accept 从未真正被调用,因为 boot.js 中的父项被调用了。难道只有1个?!

如何摆脱这个错误?

或者,让我换个说法:我如何摆脱这个错误并正确设置一个带有 redux 存储的 React 热加载环境?

可能相关的 Github 问题:

https://github.com/reactjs/react-redux/issues/259

经过进一步研究,发现问题出在boot.js中accept调用的范围。由于它本质上是从根级别应用程序观察一切,整个应用程序在 reducer 更改时重新加载,因此从未调用过 reducer 的 HMR accept。以下是工作版本。

boot.js

if (module.hot) {
    module.hot.accept('./containers/App.js', () => {
        const nextApp = require('./containers/App').default;
        renderApp(nextApp);
    })
}

configureStore.js

  if (module.hot) {
    module.hot.accept('../services/rootReducer', () => {
      const nextRootReducer = require('../services/rootReducer');
      const finalReducer = {...nextRootReducer, router: routerReducer };
      store.replaceReducer(combineReducers(finalReducer));
    })
  }