Redux - how to keep the reducer state during hot reload
14,592
Solution 1
Assuming Babel 6, you need to do something along this:
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;
}
You can see the approach in action at my redux demo.
Solution 2
Check the code related to store creation - createStore()
.
The store must be built outside app.js
, otherwise, ot will be FLUSHED each time on each HMR update.
Wrong:
// 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);
Correct:
// 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
Author by
Tomas Randus
Updated on July 15, 2022Comments
-
Tomas Randus almost 2 years
I use React + Redux + Webpack + WebpackDevserver. Once the hot loader is launched all my reducers are reseted to the initial state.
Can I keep somehow my reducers in the actual state?
My Webpack config contains:
entry: [ "./index.jsx" ], output: { filename: "./bundle.js" }, module: { loaders: [ { test: /\.js|\.jsx$/, exclude: /node_modules/, loaders: ["react-hot","babel-loader"], } ] }, plugins: [ new webpack.HotModuleReplacementPlugin() ]
My reducers stats with:
const initialState = { ... } export default function config(state = initialState, action) { ...
I start my Webpack Dev-Server just by:
"start": "webpack-dev-server",