alexisvincent / systemjs-hot-reloader

reloads your modules as needed so that you can have satisfyingly fast feedback loop when developing your app
MIT License
228 stars 36 forks source link

Hot reloading react-router #51

Closed peteruithoven closed 8 years ago

peteruithoven commented 8 years ago

I'm having having problems hot reloading the react-router. It's a commonly used Router used in combination with React. It loads the right components based on the current path.

It logs the following warning: You cannot change <Router routes>; it will be ignored when hot-loading`. Relevant issues: https://github.com/rackt/react-router/issues/2704 https://github.com/rackt/react-router/issues/2982

This isn't a systemjs-hot-reloader issue, but I'm hoping I can come to a solution with other React & Systemjs users.

Simply removing all existing DOM elements in an __unload doesn't work, React doesn't like it when you interfere with "it's" dom nodes.

Xazzzi commented 8 years ago

@peteruithoven, instead of just removing DOM elements try to unmount your root component from a dom node like this: ReactDOM.unmountComponentAtNode(container); where container is your <div> (or any other HTMLElement you are mounting your app into =)

peteruithoven commented 8 years ago

Awesome! Thanks @Xazzzi that works.

My root js file now includes the following line:

export function __unload() {
  ReactDOM.unmountComponentAtNode(container);
}

It feels like a very crude solution, but I'm hoping it prevents having to find solutions for reloading things like the Router and the Redux Provider.

capaj commented 8 years ago

@Xazzzi good idea there. Might add it to the readme.

LucaColonnello commented 8 years ago

+1

peteruithoven commented 8 years ago

@LucaColonnello what are you +1ing precisely? The crude trick is added to the readme.

LucaColonnello commented 8 years ago

@peteruithoven I +1ed the requests, the purposed solution and the idea to write it in the README. Could be really helpful!

pedramphp commented 8 years ago

The unload function took away the error but hot reloading stop working. I found a solution that works.

componentWillMount() {
        // to work with jspm-live-reload
        // a little hack to help us rerender when this module is reloaded
        this.forceUpdate()
    }

below is working example

import { Router, Route, Link, browserHistory } from 'react-router';

// load components
import Container from 'src/components/deals/Container.jsx!';
import ConfigureCustomCategory from 'src/components/deals/customCategory/ConfigureCustomCategory.jsx!';

const routeConfig = [ {
    path: '/',
    component: Container,
    childRoutes: [{
        path: '/configure-custom-category',
        component: ConfigureCustomCategory
    }]
}]

class Routes extends React.Component {
    componentWillMount() {
        // to work with jspm-live-reload
        // a little hack to help us rerender when this module is reloaded
        this.forceUpdate()
    }

    render() {
        return <Router history={browserHistory} routes={routeConfig} onUpdate={() => window.scrollTo(0, 0)} />
    }
}

export default Routes
peteruithoven commented 8 years ago

@pedramphp, what do you mean with "hot reloading stop working"?

I'm afraid you solution doesn't work for me, I keep getting the Warning: [react-router] You cannot change <Router routes>; it will be ignored warnings. Differences are that I don't define routeConfig in a separate object and I have another object around the Router; Redux's Provider.

So normally, besides the unload trick, I have the following:

const container = document.getElementById('container');
render(
  <Provider store={store}>
    <Router history={hashHistory}>
      <Route path="/" component={App}>
        <Route path="save" component={Save}/>
        <Route path="open" component={Open}/>
        <Route path="export" component={Export}/>
      </Route>
    </Router>
  </Provider>,
  container
);

I tried putting the Provider in a element with a componentWillMount handler and I also tried also putting the Router in a seperate component with also a componentWillMount handler. But both result in me still getting the warning.

class RenderForcer extends React.Component {
  componentWillMount() {
    this.forceUpdate(); // a little hack to help us re-render when this module is hot reloaded
  }
  render() {
    return (
      <Provider store={store}>
        <RouterRenderForcer />
      </Provider>
    );
  }
}
render(<RenderForcer />, document.getElementById('container'));
import React from 'react';
import { Router, Route, hashHistory } from 'react-router';
import App from './containers/App.js';
import Open from './containers/Popups/Open.js';
import Save from './containers/Popups/Save.js';
import Export from './containers/Popups/Export.js';

export default class RouterRenderForcer extends React.Component {
  componentWillMount() {
    this.forceUpdate(); // a little hack to help us re-render when this module is hot reloaded
  }
  render() {
    return (
      <Router history={hashHistory}>
        <Route path="/" component={App}>
          <Route path="save" component={Save}/>
          <Route path="open" component={Open}/>
          <Route path="export" component={Export}/>
        </Route>
      </Router>
    );
  }
}
tomasz-szymanek commented 8 years ago

+1

tiagocpontesp commented 8 years ago

+1

oledm commented 8 years ago

@pedramphp, Thank you so much!

micaelmbagira commented 8 years ago

Same for me, not working. Could you please reopen the issue because it seems to be not solved ?

capaj commented 8 years ago

@micaelmbagira I haven't seen it happening on my projects. in the last couple of months. Can you share your project/boilerplate where you see the issue occurring?

micaelmbagira commented 8 years ago

Here is a repo https://github.com/micaelmbagira/react-jspm-hot-reload so that you can easily reproduce. If I remove in src/index.js

export function __reload(m) {
  if (m.component.state) {
    component.setState(m.component.state);
  }
}
export function __unload() {
  ReactDOM.unmountComponentAtNode(container);
}

I have the error. If I add it, I don't have the error but the component is not reloaded...

hutber commented 8 years ago

@pedramphp thanks for putting that up.

However what is Container, and ConfigureCustomCategory in your example. Bit confused by those.

const routeConfig = [ {
    path: '/',
    component: Container,
    childRoutes: [{
        path: '/configure-custom-category',
        component: ConfigureCustomCategory
    }]
}]