Redux - 如何在热重载期间保持reducer状态

25

我使用 React + Redux + Webpack + WebpackDevserver。一旦热加载程序启动,所有的reducer都会被重置为初始状态。

有没有办法让我的reducer保持在当前状态?

我的Webpack配置包含:

entry: [
    "./index.jsx"
],
output: {
    filename: "./bundle.js"
},
module: {
    loaders: [
        {
            test: /\.js|\.jsx$/,
            exclude: /node_modules/,
            loaders: ["react-hot","babel-loader"],
         }
    ]
},
plugins: [
    new webpack.HotModuleReplacementPlugin()
]

我的reducers的状态为:

const initialState = {
...
}

export default function config(state = initialState, action) { ...

我只需要执行以下命令就能启动Webpack Dev-Server:

"start": "webpack-dev-server",
4个回答

21

假设使用Babel 6,你需要按照以下步骤进行:

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

export default function configureStore(initialState) {
  const store = createStore(rootReducer, initialState);

  if(module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextReducer = require('../reducers/index').default;

      store.replaceReducer(nextReducer);
    });
  }

  return store;
}
你可以在我的redux演示中看到这种方法的实际应用。

1
这似乎只支持reducers文件夹的热重载,如何为容器、组件和操作实现热重载? - ruandao
3
容器和组件可以通过react-hot-loader进行处理。虽然这是一项实验性技术。由于问题受限于reducers,因此答案也有限。 - Juho Vepsäläinen

5

检查与存储创建相关的代码 - createStore()。 存储必须在app.js之外构建,否则每次HMR更新都会被清除。

错误:

// app.js

import React from 'react';
import ReactDOM from 'react-dom';
import { hot } from 'react-hot-loader';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/lib/integration/react';
import { AppWidget } from 'containers';
import createStore from 'store/create-store';

const { store, persistor } = createStore(); // <!--- NEW STORE ON HMR, BUG

const rootElement = window.document.getElementById('appWidget');

const render = (Component) => {
  ReactDOM.render(
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <Component />
      </PersistGate>
    </Provider>,
    rootElement,
  );
};

render(process.env.NODE_ENV === 'development' ? hot(module)(AppWidget) : AppWidget);

正确:

// app.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { AppWidget } from 'containers';
import store from 'store/create-store';
import { AppContainer } from 'react-hot-loader';

const rootElement = window.document.getElementById('appWidget');

const render = (Component) => {
  ReactDOM.render(
    <AppContainer>
      <Provider store={store}>
        <Component />
      </Provider>
    </AppContainer>,
    rootElement,
  );
};

render(AppWidget);

if (module.hot) {
  module.hot.accept();
}


// create-store.js

import { applyMiddleware, compose, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
import rootSaga from './sagas';

const doCreateStore = () => {
  const sagaMiddleware = createSagaMiddleware();
  const middleware = [
    thunk,
    sagaMiddleware,
  ];

  const store = createStore(
    rootReducer,
    compose(
      applyMiddleware(...middleware),
    ),
  );

  sagaMiddleware.run(rootSaga);

  return store;
};

export default doCreateStore(); // <!-- CREATE AND RETURN STORE, NO BUG


1
这是微妙但非常重要的不同之处! - chenop

2

在根元素中渲染应用程序时,请按以下方式编写代码。

store.js:

export const store = createStore(rootReducer, integrateDevTools)

index.jsx:

这将解决问题。


ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root'),
)


if (module.hot) {
  module.hot.accept()
}

0

是的,你可以。实际上,如果你使用react-hot-loader,你将得到这个结果以及更多。

react-hot-loader会确保只更新你改变的三个部分,并且还会在redux中保留状态。

例如:你正在创建一个模态框,从API接收一些信息,然后将信息保存在redux中,如果你更改了文本颜色,你知道你必须等待整个应用程序刷新,然后浏览器渲染,然后你必须打开模态框,等待API等等。但是,使用react-hot-loader之后,当你更改了那个颜色后,你的模态框仍然会保持打开状态,显示当前数据,只有那个颜色会被更新。

按照包README中的步骤:

1- 你需要安装该包(是的,不需要成为dev依赖项,README会详细解释原因)

npm install react-hot-loader

2 - 在 .babelrc 文件中添加它

// .babelrc
{
  "plugins": ["react-hot-loader/babel"]
}

3 -App.js 文件的第一行导入 hot(是的,在 React、ReactDOM 以及所有其他内容之上),然后将您的根组件标记为热导出

// App.js
import { hot } from 'react-hot-loader/root';
const App = () => <div>Hello World!</div>;
export default hot(App);

就是这样,现在你应该有一个热重载,它只关注最后的更改并为您保留redux状态。

注意:如果您使用hooks,请查看文档此处以获取更多详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接