Alejandro Napoles

Alejandro Napoles


Thoughts and ideas about programming, technology and my life as a lifelong learner and developer.

Share


Tags


Twitter


Fixing hot reloading error in React Router

Each change in the code of my current project I was receiving the following React Router error: You cannot change <Router routes>; it will be ignored That…

Alejandro NapolesAlejandro Napoles

Each change in the code of my current project I was receiving the following React Router error:

You cannot change <Router routes>; it will be ignored

That meant that I was having to refresh the page manually, rendering the hot reloading almost useless, since the only thing updating was my CSS. Eventually I started looking around to see what other people where saying about it and how to fix this.

I found this issue, which addresses this exact error. I had some code like this:

ReactDOM.render((
 <Provider store={store}>
  <Router history={browserHistory}>
	<Route path="/" component={App}/>
	<Route path="search" component={SearchFormContainer}/>
	<Route path="product/:id" component={ProductDetailsContainer}/>
   </Router>
 </Provider> 
), document.querySelector(".app"));

When a JavaScript file changed, the router was re-rendering and therefore receiving a new set of routes, which is not supported. The user taion explains it in this related issue:

The warning was a previously missing one - something you are doing is changing the set of routes passed into your <Router>, and we currently don't support that. This is to let you know that you are doing something potentially dangerous and wrong.

We also have Dan Abramov’s contribution in the same issue:

The only reason you get this warning is because you re-render Router. You can either stop doing it and move setState (or connect in case of Redux) to the top level route handler.

Alternatively you can define your routes outside the root component’s render function.

Incidentally, I was watching one of Dan’s great Redux courses: Building React Applications with Idiomatic Redux, and applying what I was learning to my project. There’s this “episode” in which he’s explaining that it’s recommended to extract the Provider into its own component, so you have something like this:

import React from "react";
import {Provider} from "react-redux";

const Root = ({store}) =>
	<Provider store={store}>
 	  <Router history={browserHistory}>
		<Route path="/" component={App}/>
		//...
   	</Router>
	</Provider>

export default Root;

Having this Root component doesn’t make the warning disappear, we need to define the routes outside of root component, as he says above, therefore we extract the routes into a separate file, and export it in Root. Here is the simple change in the code:

import React from "react";
import {Provider} from "react-redux";
import routes from "../../routes/routes";

const Root = ({store}) =>
	<Provider store={store}>
 	  {routes}
	</Provider>

export default Root;

Extracting our routes this way fixes our error (we have our hot reloading back!) and, in my opinion, gives you a nice separation of concerns, since now Root’s only task is to pass the store to the children, without knowing anything about the routes. At the same time, if we want to modify the routes, and manage the associated dependencies, there’s one place to do it. Finally, our render function ends up like this:

ReactDOM.render(<Root store={store}/>, document.querySelector(".app"));
Comments