Once you add redux simple router (or redux router) you have two places in your state that need to be kept in synch.
import { combineReducers } from 'redux'
import { routeReducer } from 'redux-simple-router'
import tree from './tree'
//reducers/index.js
const rootReducer = combineReducers({
tree: tree,
routing: routeReducer
})
export default rootReducer
Now every time you change tree
you need to update the routing
part, that's easy because your action creators may push
a new state into the browser history.
The other way around, changing the URL and reduce correctly is a bit more complex because the router dispatches only one action (UPDATE_LOCATION
if using redux-simple-router) and based on this action you need to reduce your state correctly.
Matching -and sometimes parsing- the url in your reducers is something that feels wrong, it is a logic that doesn't belong to the reducer.
Sagas in redux are an a way to listen for redux actions and spawn side effects accordingly. I've created a couple of sagas in sagas/index.js file
.
The first one retriveNode
watches for the RETRIEVE_NODE
an action that I dispatch on the connected components, once the action is fired it executes in order some side effects, one of them being the url change provided by the push
function.
Now we need to tackle another problem, what happens when someone changes the url like when I click the back or forward button on the browser?
In that case the routing
part of our state changes but the tree
part remains the same. The solution is in the other saga called urlChanged
.
I listen to the UPDATE_LOCATION
action and check if this action has been a POP, a POP action is our way to say: Did this action occur has a result of a back / forward navigation or it was intenionally pushed. This prevents executing ina loop both sagas.
Once the url changed as a result of the back / forward button we retreive
the node, this will wake up the retriveNode
saga and re build our state correctly.