larrymyers / react-mini-router

A minimal URL router for React.js
MIT License
282 stars 38 forks source link

Catching manual url changes #44

Closed kwebster16 closed 8 years ago

kwebster16 commented 8 years ago

I'm in the process of writing an app that needs to respond to manual changes in the url - which it does currently. However that response is almost always going to involve a change in state (and a async backend call).

Simplified example:

mixins: [Reflux.connect(Store, 'store'), MiniRouter.RouterMixin],
  routes: {
      '/': 'home',
      '/:tt_id': 'tt',
      '/:tt_id/:term_id': 'term'
  },

I've inserted calls to the store in appropriate places when the user is navigating within the app and that works fine. However my issue comes up with the user is on say /2/2 and then manually changes to /2/1. The render component for the navigation fires however I can't update state there otherwise it obviously causes a render loop. Since the component is already rendered getInitialState won't work. Is there another place you can suggest putting this call?

larrymyers commented 8 years ago

my suggestion is to handle the state change outside the component, likely in the component with the router mixin.

  1. detect the dirty state, and render a "loading" component instead of the component that handles this specific data.
  2. in a setTimeout call issue a state change through your data store to get the correct data and trigger another render. the setTimeout will allow you to avoid an error by changing state inside a render.
  3. once you have your app in the correct state with the new data, let it render normally.
kwebster16 commented 8 years ago

I'm still not sure where I can hook into that manual url change event though? More code... This is essentially what the parent component would look like. Each child component is also getting it's state directly from the store.

export default React.createClass({

  mixins: [Reflux.connect(Store, 'store'), MiniRouter.RouterMixin],
  routes: {
      '/': 'home',
      '/:tt_id': 'tt',
      '/:tt_id/:term_id': 'term'
  },
  home: function() {
    return (
      <HomeComponent/>
    )
  },
  tt: function(id) {
    return (
      <TTComponent/>
   )
  },

  term: function(tt_id, term_id){
    return (
      <termComponent />
   )
  },

  render: function() {
    return this.renderCurrentRoute();
  }
larrymyers commented 8 years ago

I'm not familiar with Reflux, but wherever you are getting data from to render the component, that code path is where you need to recognize the stale data compared to the current url, render the loading component, and trigger a new event loop by fetching updated data.

larrymyers commented 8 years ago

See the included example app:

https://github.com/larrymyers/react-mini-router/blob/master/example/app/components/app.jsx

Note how the data for each component that is associated with a route is directly passed in as a parameter. This makes it easy to decouple stale data state changes and the rendering of components.