react-hot-loader: You cannot change ; it will be ignored

Hi, I cannot seem to setup the hot reloading. It actually works, but I keep getting the error in console You cannot change <Router routes>; it will be ignored

This is my router file

import React from 'react';
import ReactDOM from 'react-dom';

import {Provider} from 'react-redux';
import {Router, browserHistory} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import { getRootNode } from '../../helpers/routing_helpers';

// Components

// Hot reload
import { AppContainer as HotLoaderAppContainer } from 'react-hot-loader';
import AppRoutes from './routes';

export default function (inject: Function, {Store}: IContext) {
  const history = syncHistoryWithStore(browserHistory, Store);

  const renderApp = (CurrentAppRoutes: any) => {
    ReactDOM.render(
      <HotLoaderAppContainer>
        <Provider store={Store}>
          <Router history={history}>
            { CurrentAppRoutes }
          </Router>
        </Provider>
      </HotLoaderAppContainer>,
      getRootNode('react-root')
    );
  };

  renderApp(AppRoutes);

  if (module.hot) {
    module.hot.accept('./routes.jsx', () => {
      const NextAppRoutes = require('./routes').default;
      renderApp(NextAppRoutes);
    });
  }
};

And a routes file

import React from 'react';

import {Route, IndexRoute } from 'react-router';

// Components
import Layout from './components/layout';
import HomePage from './components/home_view';
import ProfilePage from '../user/components/profile_view';

const AppRoutes = (
  <Route path="/" component={Layout}>
    <IndexRoute component={HomePage} />
    <Route path="profile" component={ProfilePage} />
  </Route>
);

export default AppRoutes;

Would you be able to help please?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 31 (1 by maintainers)

Most upvoted comments

My “solution” is to override the console.error, and filter the warning out. It’s only included when HMR is enabled.

/**
 * Warning from React Router, caused by react-hot-loader.
 * The warning can be safely ignored, so filter it from the console.
 * Otherwise you'll see it every time something changes.
 * See https://github.com/gaearon/react-hot-loader/issues/298
 */
if (module.hot) {
  const isString = require('./utils/checks').isString;

  const orgError = console.error; // eslint-disable-line no-console
  console.error = (...args) => { // eslint-disable-line no-console
    if (args && args.length === 1 && isString(args[0]) && args[0].indexOf('You cannot change <Router routes>;') > -1) {
      // React route changed
    } else {
      // Log the error as normally
      orgError.apply(console, args);
    }
  };
}

I think this issue should this be kept open util it’s officially fixed?

Was this officially fixed yet?

If others, like me, encounter this when trying to add hot reloading to your react-router based React project from create-react-app, the much simpler solution is to make this change (to index.js):

diff --git a/songsearch/client/src/index.js b/songsearch/client/src/index.js
index 954ab34..4c047b1 100644
--- a/songsearch/client/src/index.js
+++ b/songsearch/client/src/index.js
@@ -9,14 +9,26 @@ import 'bootstrap/dist/css/bootstrap.css';
 import './index.css';
 
 
+class Root extends React.Component {
+  render() {
+    return (
+      <Router history={browserHistory}>
+        <Route path='/' component={App}>
+          <IndexRoute component={Home} />
+          <Route path="/q/:q" component={Home}/>
+          <Route path="/song/:artist/:name/:id" component={Song}/>
+          <Route path='/about' component={About} />
+        </Route>
+      </Router>
+    )
+  }
+}
+
 ReactDOM.render(
-  <Router history={browserHistory}>
-    <Route path='/' component={App}>
-      <IndexRoute component={Home} />
-      <Route path="/q/:q" component={Home}/>
-      <Route path="/song/:artist/:name/:id" component={Song}/>
-      <Route path='/about' component={About} />
-    </Route>
-  </Router>,
+  <Root/>,
   document.getElementById('root')
-);
+)
+
+if (module.hot) {
+  module.hot.accept()
+}

The trick is the simplicity of the module.hot.accept() and that you need to put make the first block a component instead of a block of <Router>.

All those are temporary solutions, but have you tried adding a key to the Router component, like e.g. here https://github.com/reactjs/react-router/issues/2704#issuecomment-211352123 ? I haven’t tried that myself, but seems to be a good workaround, since the problem is rerendering. I have also seen a variant of this solution with key={ Math.rand() } , which is surely wild, but less fuss.

@tsaiDavid Any fix for your problem? I have the same issue: console shows this

[HMR] Updated modules:

process-update.js:102 [HMR]  - ./src/components/App.js

process-update.js:107 [HMR] App is up to date.

but my App component is not updated

Any luck on this ?

My Routes file has the following:

<Router history={hashHistory}>
        <Route path="/" component={Main} />
        <Route path="/jobdescription/:id" component={JobDescriptionContainer} />
        <Route path="/apply/:jobdescription" component={ApplicationForm} />
        <Route path="/thankyou" component={ThankYou} />
</Router>

If you are having this issue this is most likely due to createBrowserHistory being in the same file you accept in the HMR. Since the entire file specified will be reloaded, there will be a new history created on each HMR refresh and you will get the error. The simple solution is to create history in a separate file and import it.

If others, like me, encounter this when trying to add hot reloading to your react-router based React project from create-react-app, the much simpler solution is to make this change (to index.js):

diff --git a/songsearch/client/src/index.js b/songsearch/client/src/index.js
index 954ab34..4c047b1 100644
--- a/songsearch/client/src/index.js
+++ b/songsearch/client/src/index.js
@@ -9,14 +9,26 @@ import 'bootstrap/dist/css/bootstrap.css';
 import './index.css';
 
 
+class Root extends React.Component {
+  render() {
+    return (
+      <Router history={browserHistory}>
+        <Route path='/' component={App}>
+          <IndexRoute component={Home} />
+          <Route path="/q/:q" component={Home}/>
+          <Route path="/song/:artist/:name/:id" component={Song}/>
+          <Route path='/about' component={About} />
+        </Route>
+      </Router>
+    )
+  }
+}
+
 ReactDOM.render(
-  <Router history={browserHistory}>
-    <Route path='/' component={App}>
-      <IndexRoute component={Home} />
-      <Route path="/q/:q" component={Home}/>
-      <Route path="/song/:artist/:name/:id" component={Song}/>
-      <Route path='/about' component={About} />
-    </Route>
-  </Router>,
+  <Root/>,
   document.getElementById('root')
-);
+)
+
+if (module.hot) {
+  module.hot.accept()
+}

The trick is the simplicity of the module.hot.accept() and that you need to put make the first block a component instead of a block of <Router>.

This causes whole page re-render not the changed component

Well, @thebuilder, thanks for handing me the plastic bag to put over this this annoyances head. That’s one way to go about it lol. I’d keep this issue open though until an official fix comes along.

@akhayoon where ever you want - i have it in my app.js file.

Yes I tried that and it most certainly helps 😉 But, if you add a different key with module reload, you will lose a state and the whole react-hot-reload is kind of useless then ;/