version 3 loses component local state
See original GitHub issueI have an accordion that has local state that tracks which panes are open. When I update one of the panes, the open panes collapse because (I’m assuming) the accordion’s state is being set back the default state.
There are many moving pieces so I’m not sure what to point out. I’m using webpack-dev-middleware, webpack-hot-middleware, and my config looks like this:
const config = Object.assign({}, projectConfig, {
entry: [
"webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&quiet=true",
"react-hot-loader/patch",
path.join(__dirname, "../public/js/main.js")
]
});
config.plugins = config.plugins.concat([
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]);
config.module.loaders = config.module.loaders.concat([
{ test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: "react-hot-loader/webpack" }
]);
// ...
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
noInfo: true,
stats: {
colors: true
}
}));
app.use(webpackHotMiddleware(compiler, {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10 * 1000
}));
My component files are definitely being transformed, here is a snippet:
// ...
module.exports = connect(
(state, props) => ({
breakpoints: _getBreakpoints(state)
}),
dispatch => bindActionCreators(actions, dispatch)
)(Breakpoints);
;(function () { /* react-hot-loader/webpack */ if (process.env.NODE_ENV !== 'production') { if (typeof __REACT_HOT_LOADER__ === 'undefined') { return; } if (typeof module.exports === 'function') { __REACT_HOT_LOADER__.register(module.exports, 'module.exports', "Breakpoints.js"); return; } for (var key in module.exports) { if (!Object.prototype.hasOwnProperty.call(module.exports, key)) { continue; } var namedExport = void 0; try { namedExport = module.exports[key]; } catch (err) { continue; } __REACT_HOT_LOADER__.register(namedExport, key, "Breakpoints.js"); } } })();
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(17)))
Finally, how I render the root component:
function renderToolbox() {
ReactDOM.render(
React.createElement(
AppContainer,
null,
React.createElement(
Provider,
{ store },
React.createElement(require("./components/TabList"))
)
),
document.querySelector("#mount")
);
}
if(module.hot) {
module.hot.accept('./components/TabList.js', () => {
renderToolbox();
});
}
Looking at AppContainer, I don’t see where it would save local state. I’m requiring the new version of TabList which ends up requiring the new version of my component, and it appears to just be re-rendering my whole app with the new component, and I don’t see where state is transferred across these instances.
Issue Analytics
- State:
- Created 7 years ago
- Comments:23 (6 by maintainers)

Top Related StackOverflow Question
TLDR: don’t use
withRouterfor the exported component used as as top level route component withreact-router(and theRouter)Just wanted to report what was the problem in my case causing local state to be lost with RHL3: The top level component we passed to our
react-routerRoutercomponent (same problem with react-router 3 and 4) was anAppcomponent that itself was exported via awithRouter(App)HOC (withRouter fromreact-router). I eventually discovered that this caused theAppcomponent to get re-mounted on every HMR cycle (save), causing the local state everywhere to be lost.Solution for us: Move the
withRouterwrapping to sub components; don’t use it with the top level component put inside theRouter. Now HMR works and local state is kept.Note for point of interest: we were, and still are, wrapping our App export in an
connect- this does not cause any problem. Not sure exactly whatwithRouterdoes that causes this problem.Cool, that makes perfect sense. But it’s still quite a problem for me 😦 Not exactly sure how to approach it as: a) I am using swesome-typescript-loader so can’t use that babel plugin b) I have so many of these I’ll tear half of my hair out before I’d manage to do it all manually.
was this always a no no with hmr? I could have sworn this was working at some point in time. Maybe the principles of that plugin could be used to build a lib that could deconstruct these in a fashion that wouldn’t force one to use babel. I’d have to think about it a bit.
For dev experience, I guess I could fake the initial state to “working state” to allow me to work with HMR, it’s a bit of a pain though