acdlite / redux-router

Redux bindings for React Router – keep your router state inside your Redux store
MIT License
2.3k stars 216 forks source link

Resolve route handler purely through Redux state #207

Closed rybon closed 8 years ago

rybon commented 8 years ago

I'm having trouble understanding how Redux Router reconciles the way React Router and Redux work. With React Router, whenever the URL (which is state) changes, it calls a callback to render the appropriate RouteHandler into a container. With Redux, whenever a dispatch action changes the state in the store, the entire UI rerenders and based on the props the appropriate React components render. From the Redux approach, we can conclude the UI is always a function of the state in the store, and the store is always a function of a sequence of dispatched actions. This is great, because it means we can always recreate the exact same UI state by replaying the dispatched actions in the same order. In other words, the Redux UI is idempotent.

But changing the RouteHandler is not covered by these actions, because that is done through a separate callback provided to React Router. From what I understand, Redux Router solves this problem by listening to certain types of dispatches and subsequently calling React Router from the middleware to change the actual route. This is potentially problematic when replaying a sequence of actions (for example during a test suite), as this means the React Router life cycle callbacks will be called again, in which side effects such as data loading may be performed. These side effects may trigger additional dispatches, clobbering the sequence of actions we are trying to replay. This breaks the idempotence of the Redux UI.

A way to get around that problem is to treat route changes as just another state change, dispatch an action, mutate the state in the router reducer and resolve the correct route handler based on the props inside the container, as opposed to doing it in a separate callback. That way, the React Router life cycle callbacks are skipped* and we can replay route changes in an idempotent way as well. This seems a more natural React approach than hooking up a bit of middleware to listen to certain action types and call into React Router. How do I achieve this with Redux Router? Am I missing something here?

*which also means we have to perform our side effects somewhere else

I opened another issue in the React Router repo a while back that explains it further: https://github.com/rackt/react-router/issues/2045

Scarysize commented 8 years ago

Hey, I see - and I think understand - your concern. Though this seems like a issue which requires a more major overhaul, I don´t see it getting solved any time soon. Because redux-router is currently not "really" maintained. We do accept PRs though. Concerning your problem: You might want to try redux-simple-router, it´s a much simpler attempt and it is actively maintained; James releases v1.0 only recently. From what I hear, the refactor from this router to simple-router isn´t that much of a pain, too. The other option is of course, for you to fork this repo and adapt it the way you want.

Hope this helps, if so please close this issue :-)