React-hot-loader: react hot loader v4 hot HOC

Created on 22 Mar 2018  路  3Comments  路  Source: gaearon/react-hot-loader

Description

What you are reporting:
react hot loader v4 hot HOC bug with react-redux Provider

Expected behavior

What you think should happen:
work well

Actual behavior

What actually happens:

  1. use react-hot-loader v4 hot HOC

configureStore.js

const configureStore = (initialState) => {
  const store = createStore(
    reducer,
    initialState,
    middleware,
  );
  if (module.hot) {
    module.hot.accept('./reducers', () => {
      // eslint-disable-next-line global-require
      const nextRootReducer = require('./reducers').default;
      store.replaceReducer(nextRootReducer);
    });
  }

  return store;
};
export default configureStore;

router.js

import { hot } from 'react-hot-loader';
import React from 'react';
import configureStore from 'redux/configureStore';

const store = configureStore();

const App = () => {
  return (
    <Provider store={store}>
      {/* ... */}
    </Provider>
  );
};

export default hot(module)(App);

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './router';

ReactDOM.render(
  <App />,
  document.getElementById('root'),
);

when hot loader
image

<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.
  1. use react-hot-loader v3 AppContainer
    > router.js
import React from 'react';
import configureStore from 'redux/configureStore';

const store = configureStore();

const App = () => {
  return (
    <Provider store={store}>
      {/* ... */}
    </Provider>
  );
};

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import App from './router';

const render = (Component) => {
  ReactDOM.render(
    <AppContainer>
      <Component />
    </AppContainer>,
    document.getElementById('root'),
  );
};

render(App);

if (module.hot) {
  module.hot.accept('./router', () => {
    // eslint-disable-next-line global-require
    const newApp = require('./router').default;
    render(newApp);
  });
}

Then the hot update will not have an error message.

Temporary solution for v4

add random key to Provider

before

<Provider store={store}>
  {/* ... */}
</Provider>

after

<Provider store={store} key={Math.random()}>
  {/* ... */}
</Provider>

Environment

React Hot Loader version:

Run these commands in the project folder and fill in their results:

  1. node -v: v8.2.1
  2. npm -v: 5.6.0

Then, specify:

  1. Operating system: macOS Sierra
  2. Browser and version: chrome 65.0.3325.162

Most helpful comment

There is nothing we could do. There is nothing we could change, as long things are working as the supposed to work.

You are reloading a file, that file re-creates the store, dropping all the information inside, Redux Provider warns you about that action and next RHL will prevent componentDidMount to fire, and you will never fill the store again.

There is a general rule - __you shall not hot reload application initialization code__. Including store creation and react-dom/render.

How to fix

const App = () => {
  return (
    <Provider store={store}>
      {/* ... */}  <--- take this
    </Provider>
  );
};

And extract to another file. And mark as _hot_ that file.

So you will be able to reload reducers and application __not__ simultaneously, will not recreate store on HMR even, and achieve the goal.

All 3 comments

There is nothing we could do. There is nothing we could change, as long things are working as the supposed to work.

You are reloading a file, that file re-creates the store, dropping all the information inside, Redux Provider warns you about that action and next RHL will prevent componentDidMount to fire, and you will never fill the store again.

There is a general rule - __you shall not hot reload application initialization code__. Including store creation and react-dom/render.

How to fix

const App = () => {
  return (
    <Provider store={store}>
      {/* ... */}  <--- take this
    </Provider>
  );
};

And extract to another file. And mark as _hot_ that file.

So you will be able to reload reducers and application __not__ simultaneously, will not recreate store on HMR even, and achieve the goal.

I had this problem as well. I'm posting the exact error message so it can be found in search (I had a hard time finding this thread that solved it for me).

This is the error I received when trying to hot-reload like the OP:

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

Just put hot into the "next" file. Don't reload store creation. We are React, not Redux hot-loader :)

Was this page helpful?
0 / 5 - 0 ratings