I need to redirect from the currently matched route component to another route, and was using router.push for that. But turns out that redirection happens only on the client side, and I lose the benefits of Isomorphic rendering.
Past solutions I could find used the older syntax with onAbort etc, which doesn't seem to exist in the present version anymore. This is a real world problem that I suppose must have some solution?
@shubhamsizzles The way I've handled this was by creating an onEnter(nextSate, replace, callback) hook that uses the replace argument to redirect the user as needed. I'm curious as to the proper way to do this as well.
@FuzzySockets Well that could work for simple cases. In my case, the state machine looks like -
1) Fetch data for all decorated componenents and store in redux
2) Then, render the matching route
2a) Matching route reads redux store, and does an appropriate redirect to another route.
Therefore, providing hooks may not work as at that instant I may not have access to redux store.
@shubhamsizzles Sounds pretty similar to my system. Where exactly are your redirect statements? I used to have mine in the components themselves, but that proved difficult to maintain since the client and server was always out of sync by the time they got to redux. So instead, I check everything right after the user navigates, in the onEnter hook.
It's here that I decide whether or not the user should continue. If they should, I fire an asynchronous action to retrieve the data, set an isLoading flag, and upon response, set isLoading to false; simultaneously, I redirect the user to the route in question. If their credentials lack, it's here that I use the replace method to redirect them accordingly.
I call store.getState().someReducer from the onEnter hook. The trick is you have to make sure you initialize the store on the server with data that will result in the same state. There is a bit of juggling, but I've managed to work it.
@FuzzySockects I have a catchall route, that connects to redux store, matches current url with redux store contents in constructor, and on componentWillMount, it redirects to a route using .push
@shubhamsizzles So is the problem that .push isn't available? Or that your server state is not resulting in the redirect? I was unable to get history.push(state) to work at all. The redirects only started happening when I moved the logic to an onEnter()
@FuzzySockets How do you make sure that redux is populated before onEnter ? Doesn't onEnter happen as soon as you do a match({routes, location}) but fetching data for redux occurs only inside the match callback (please correct me if I'm wrong)
@FuzzySockets .push is available ofcourse, but it only comes into action on client side. On the server, its almost like the call is getting ignored.
@shubhamsizzles Wow, you're right, redux is populated after onEnter. It must be loading fast enough so that the client takes over and applies the correct state. Weird, usually I see a flash of the other component when I come across this:
warning.js:44Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(server) id="27">
(client) id="27">FuzzySockets on 12 Apr 2016
Another oddity is that I just tried the same thing 5 more times in a row and did not receive that console error.
I'm guessing it's going to come down to grabbing router from context and using push from your component.
this.context.router.push(...)
See if this helps https://github.com/reactjs/react-router/blob/master/upgrade-guides/v2.0.0.md#no-default-history you at all? I'm going to try it now.
@FuzzySockets disable JavaScript in your browser and load the page, or simply do view-source://localhost:<port> in chrome to see the SSR markup
The redirection comes from your onEnter/onChange hooks.
However, the issue of prefetching data to populate your store before rendering is really out of scope here. There are some great libraries available to help with this, such as react-refetch and redial. I suggest looking into those and adapting them to your needs.
@FuzzySockets i was infact grabbing router from context itself. Doesn't seem to help here.
@shubhamsizzles I can't get redirection to occur in my components at all, whether through this.context.router.push or history.push
@timdorr This isn't just a "data prefetching" problem. redial, react-refetch, react-transmit, react-resolver etc. all populate data stores only after route matching, so onEnter is not really helpful. (I am already using redial btw)
In any other server - side framework PHP / Rails, you can issue a server redirect at any point of time while rendering a template, which react router doesn't provide an option for currently.
Also there have been several multiple issues in the past #621, #947 and projects react-router-server-location highlighting the same problem although most of the solutions don't work now.
I don't think simply closing the issue is going to help either.
It's not impossible to solve. Pass a higher order function into the onEnter hook that takes in the empty configured store. Inside, subscribe to the store, fire whatever actions you need against it, then fire the callback inside of your subscriber, which can react to whatever state the store ends up on. onEnter is async, so you can defer until redux has run inside of the hook. Once you have it working, you can wire up some convenience functions to reduce your boilerplate.
@timdorr Genius... I have to give this a try.

@timdorr The server just hangs with this. Can you explain what you mean by a pass a higher order function into the onEnter hook? I'm just using the third argument that gets passed into onEnter.
Looks good on my end now. I had to store the initial state on window within in the rendered html and pass it to createStore on the client side. Took a lot of tweaking, but this is much nicer than firing off a bunch of redux action creators on the server side.
Most helpful comment
@FuzzySockets Well that could work for simple cases. In my case, the state machine looks like -
1) Fetch data for all decorated componenents and store in redux
2) Then, render the matching route
2a) Matching route reads redux store, and does an appropriate redirect to another route.
Therefore, providing hooks may not work as at that instant I may not have access to redux store.