STRML / react-router-component

Declarative router component for React.
http://strml.viewdocs.io/react-router-component
MIT License
873 stars 94 forks source link

Updating state while inside navigation callback breaks router #145

Closed ghost closed 9 years ago

ghost commented 9 years ago

For my main component, I was hoping to be able to update its state so that it's able to track the current route. Unfortunately when attempting to call setState from within the onBeforeNavigation callback, or the onNavigation callback, it breaks the router. It appears to go into RouterMixin's getRouterState method, which doesn't normally happen during the callbacks.

I'm assuming my own setState call wipes out the router's state for whatever reason, which causes it to appear to be 'stuck' on the initial route, even though the URL updates successfully.

Ultimately the core purpose of this is to update my navbar in response to routing changes. I've tried using custom Link components however as I use server-side rendering the Router ends up using a DummyEnvironment which causes checksum inconsistencies when everything's loaded client-side, which basically eliminates any possibility of server-side rendering.

Is there any way to achieve this for my use case?

STRML commented 9 years ago

Hey @lyptt,

Perhaps a code sample would help me visualize what you are speaking about, but I believe your issue is related to setting the path param on the Router, which you should never do unless server rendering.

When I server render an app with RRC, I pass a currentRoute attribute in the initial data payload. I then do something like:

render: function() {
  // ....
  return (
    <Locations path={process.browser ? undefined : this.state.currentRoute}>
     {/* ... */}
    </Locations>
  );

On the onBeforeNavigation callback, I trigger an action in my stores that updates currentRoute, and I pass that to other components that use it (like a navbar or sidebar might for highlighting the active page).

I hope this helps.

ghost commented 9 years ago

Hi @STRML,

That path bit seemed to fix a lot of my issues, thanks! Yes it seemed to be using that browser-side too, which was probably causing things to get a little crazy.

Another thing I'm wondering is how I can determine what 'route' I'm using. I can't use the path given in onBeforeNavigation, as this is what's in the address bar, which won't match up against the path parameter in my <Location> element. For now I've added an extra prop 'route', which I'm accessing like this:

onBeforeNavigation: function(path, context) {
    this.setState({
        currentRoute: context.match.route.props['route']
    });
}

This seems a bit hacky though, is there a more official way to go about identifying the currently navigated route?

STRML commented 9 years ago
onBeforeNavigation: function(path, context) {
    this.setState({
        currentRoute: path
    });
}

?

Could you explain more about "as this is what's in the address bar, which won't match up against the path parameter in my <Location> element"?

ghost commented 9 years ago

Sure, so for example if my route is /login/:id, the callback will pass back an interpolated path like /login/0. I want to figure out what the original route was from the callback, which is why I'm currently using a prop to do it.

STRML commented 9 years ago

Ah, so you want "/login/:id"? Rather than repeating yourself with another prop, you should be able to use context.match.route.props.path.

ghost commented 9 years ago

That'll work. Thanks!