Our current Redux state tree is this:
{
"dog": {
"name": "Barkley",
"age": 6,
"hungry": false,
"location": "Living Room",
"height": "36 in."
},
"cat": {
"name": "Sir Eatsalot",
"age": 10,
"hungry": false,
"location": "Living Room",
"height": "18 in."
}
}
We receive updates from a server (via Saga) which sends us all the data relevant to the app, regardless of whether it has updated.
We receive this response type every second so that our app state matches the server state. Example response:
{
"pets": {
"dog": {
"owner": "Jim",
"petName": "Barkley",
"currentAge": 6,
"hungry": false,
"room": "Living Room",
"height": "3 ft."
},
"cat": {
"owner": "Jim",
"petName": "Sir Eatsalot",
"currentAge": 10,
"hungry": true,
"location": "Kitchen",
"height": "1.5 ft."
}
}
}
We need to take the new status and update our store.
NOTES:
- The server isn't ours, so we have to handle the responses in this format
- We don't make requests to the server, it just continually sends POSTs to us with full "here's what's happening in my application" type status update
- Server response format isn't the same as our store format, we store only the data we need and in the format we need it; i.e. mutations
Which Redux implementation is better to handle the updates:
Option 1
Have the Saga compare the current response to the previous response and dispatch actions (sometimes multiple) based on the changes.
In this case we would see that cat.hungry
and cat.location
have changed so we would dispatch two actions.
Issues
- Saga is responsible for tracking it's response state to compare the previous state to the current one
- The overhead of comparing previous state to current state will be high, the status object in our project is much bigger than this example and occurs 6 times per second; I'm not sure worrying about the overhead here is valid because it forces redundant processing on the reducers anyway.
- Just because the new status to dispatch has some data that hasn't updated doesn't mean we shouldn't ensure the data is as the server tells us it should be--the saga knows nothing about the state and should assume that it could be different from the last status update.
Option 2
Have the Saga dispatch a single UPDATE_PET_STATUS
action with the entire response and let the individual catReducer
and dogReducer
handle the full status within action.status
, pulling out it's relevant data and updating the state as needed.
Issues
- The
dogReducer
receives information meant for other states (cat state) - The
dogReducer
processes the action and checks (or updates) it's own state against the action payload without making any changes--redundant processing. - Every reducer handling this has to sift through the full raw response data
Option 3
Have a petStatusReducer
that receives the single UPDATE_PET_STATUS
action, separates and mutates the action payload and passes it down to the child reducers, dogReducer
and catReducer
.
Issues
- I think this goes against the rules around designing reducers; don't mutate arguments, don't perform side-effects. In this case we're triggering different actions by passing a different action, or at least different action data, to the child reducer.
Thoughts?
Updates: Updating Normalized Data talks about handling data somewhat similar to this...