【问题标题】:Redux - how to keep the reducer state during hot reloadRedux - 如何在热重载期间保持减速器状态
【发布时间】:2016-04-11 21:00:52
【问题描述】:

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

我能以某种方式将我的减速器保持在实际状态吗?

我的 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()
]

我的减速器统计数据:

const initialState = {
...
}

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

我只是通过以下方式启动我的 Webpack 开发服务器:

"start": "webpack-dev-server",

【问题讨论】:

    标签: webpack redux webpack-dev-server react-hot-loader


    【解决方案1】:

    是的,你可以,实际上,如果你使用 react-hot-loader,你会得到准确的结果,甚至更多。

    react-hot-loader 将确保只更新您更改的那三个,并且还将保持 redux 上的状态。

    示例:您正在创建一个模式,从 API 接收一些信息,然后将信息保存在 redux 上,如果您更改文本颜色,您知道您将不得不等待整个应用程序刷新,然后浏览器渲染,然后您必须打开模态,等待 API 等。但是 使用 react-hot-loader,更改颜色后,您的模态仍将打开,使用您当前的数据,并且只是会更新该颜色。

    按照包自述文件中的步骤操作:

    1 -您需要安装包(是的,不需要是开发依赖项,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 状态。

    OBS:如果您使用钩子,请查看更多详细信息here on the docs

    【讨论】:

      【解决方案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()
      }
      

      【讨论】:

        【解决方案3】:

        检查与商店创建相关的代码 - createStore()。 store 必须建在app.js 之外,否则每次 HMR 更新时 ot 都会被 FLUSHED。

        错误:

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

        【讨论】:

        • 这是微妙但非常重要的不同!
        【解决方案4】:

        假设 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 demo 上查看实际使用的方法。

        【讨论】:

        • 这个好像只支持reducers文件夹热重载,容器、组件和动作如何热重载?
        • 容器和组件可以通过react-hot-loader。不过,这有点实验性技术。这个问题仅限于减速器,所以这就是有限答案的原因。
        猜你喜欢
        • 2016-11-24
        • 2021-02-03
        • 2016-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-12-17
        相关资源
        最近更新 更多