kuu12 / less-router

A very easy React router component but fully functional.
https://kuu12.github.io/less-router/
MIT License
5 stars 0 forks source link

Fail on Hot reload #1

Open Calderis opened 6 years ago

Calderis commented 6 years ago

Hi,

It seems that less-router fail while hot-reloading with a webpack conf (or a storybook one).

TypeError: Cannot read property 'route' of null
    at Route.del (http://localhost:9001/static/preview.bundle.js:247160:29)
    at Route.componentWillUnmount (http://localhost:9001/static/preview.bundle.js:247123:18)
    at callComponentWillUnmountWithTimer (http://localhost:9001/static/preview.bundle.js:124926:12)
    at HTMLUnknownElement.callCallback (http://localhost:9001/static/preview.bundle.js:110470:14)
    at Object.invokeGuardedCallbackDev (http://localhost:9001/static/preview.bundle.js:110520:16)
    at invokeGuardedCallback (http://localhost:9001/static/preview.bundle.js:110573:31)
    at safelyCallComponentWillUnmount (http://localhost:9001/static/preview.bundle.js:124933:5)
    at commitUnmount (http://localhost:9001/static/preview.bundle.js:125165:11)
    at commitNestedUnmounts (http://localhost:9001/static/preview.bundle.js:125196:5)
    at unmountHostComponents (http://localhost:9001/static/preview.bundle.js:125453:7)

Fail at each change. Can work back if refreshing browser.

kuu12 commented 6 years ago

@Calderis

Thank you for reporting this issue.

The root component stores global states of less-router. If the whole root component is in the control of react-hot-loader, these states will be lost on reloading.

I didn't expect this case. But fortunately, there is an easy way to fix the problem.

// Entry point, for example
import ReactDOM from 'react-dom';
import RootComponent from './root-component.js';

const render = () => ReactDOM.render(<RootComponent />, document.body);
render();

if(module.hot) module.hot.accept('./root-component.js', render);
  // root-component.js
  import { hot } from 'react-hot-loader';
  import Routing from 'less-router';
  class RootComponent extends React.Component {
    ...
  }
- export default hot(module)(Routing(RootComponent));
+ export default Routing(hot(module)(RootComponent));

Move Routing outside of hot(module). Now react-hot-loader only controls the content of root component, global states are safe.

Calderis commented 6 years ago

@kuu12

Thks for the quick reply.

I'll try and come back asap. Hope it will works with the storybook configuration that is a kind of a black box.

Otherwised, won't it be possible to handle the lost of the global state by re-initializing it if lost ?

kuu12 commented 6 years ago

@Calderis

react-hot-loader causes some side effects, lifecycle of less-router is in a mess.

BTW, are you trying to put a component, which is wrapped by Routing, into storybook as a story?

Calderis commented 6 years ago

@kuu12

Here my story :

storiesOf("Widgets", module).add(
  "GarbageCollection",
  withInfo(Readme)(() => <Widget />)
);

Where Widget is

const Widget = ({ router }) => (
  <Header router={router} pathname={router.pathname}>
    <div
      className={`${styles.group} ${
        widgetStyles.group
      } widget widget-garbage-collection`}
    >
      <div className="widget-container">
        <Search path="/" />
        <Index path="/index" />
        <Detail path="/detail" />
        <Calendar path="/calendar" />
      </div>
    </div>
  </Header>
);

Widget.propTypes = {
  router: PropTypes.shape({}).isRequired
};

export default Routing(Widget);

As you can see, Widget is effectively wrapped by routing and called inside a story

NB: Sorry for late response though 🤭, but I was still testing on my side