Monday, April 3, 2017

React Stateless Components used for Routes don't work with Hot Module Replacement

This article is relevant for: 
- react 15.4.2
- react-router 3.0.0
- webpack 2.2.1
it may or may not work for other versions.



I've had this issue many times in the past and yet I cant seem to find a proper solution. I'm documenting it here so it may be of help to others who have hit this roadblock and drank themselves silly.

This Github issue seems to relate to this as well...

Say you are using React, React-Router and Hot Module Replacement via webpack.

You many have a combination of React components that inherit from React.Component and Pure Components.

So a React Class Component like so (e.g. ProfileComponent)

class Profile extends Component {
  render() {
    return (
      <div>
        <h1>Profile</h1>
      </div>
    );
  }
}

And a "Pure" React components (e.g. DashboardComponent)

export default () => {
  return (
    <header>
      <h1>Dashboard</h1>
    </header>
  );
};

And let's say you configure React Router to expose these Components based of these routes.

const Routes = [
  {
    path: '/',
    component: App,
    indexRoute: { component: HomeComponent },
    childRoutes: [
      {
          path: '/profile',
          component: ProfileComponent
      },
      {
          path: '/dashboard',
          component: DashboardComponent
       }
    ]
  }
];

ReactDOM.render (
    <Provider store={store}>
      <Router routes={routes} history={history} />
    </Provider>,
    document.getElementById('root')
  );


In the above example, Hot Module Replace will NOT work for "DashboardComponent" but it will work fine for "ProfileComponent".

This seems to be well known issue actually with no obvious fix.

The issue seems to be related to the "first level" Route Component specified by a React Router Route and where this "first level" component cannot be a Pure Component!

But nested 2nd, 3rd or Nth lower level components for a Route can be Pure and Hot Module Replacement will work fine.

e.g let say this ProfileComponent actually nested a Pure Component called <Button>

class Profile extends Component {
  render() {
    return (
      <div>
        <h1>Profile</h1>
        <Button />
      </div>
    );
  }
}

And Button was this:

export default () => {
  return (
    <div>
      <h1>Button</h1>
    </div>
  );
};

You can update anything in <Button> and it will work with Hot Module Replacement.

So in summary, until this issue has been solved (if it has then please send me a comment) make sure that your "first level" Route Components are NOT Pure....

Annoying? Yes.... and I feel your pain. 

No comments:

Post a Comment

Fork me on GitHub