Redux nested state design - redux

Currently having a state which is getting more complicated an I'm wondering if i'm doing it wrong, see below for an example of a reducer i'm using.
case RECEIVE_DEPARTMENT_DAYDATA:
return {
...state,
departments: {
...state.departments,
[action.payload.targetDepartment]: {
...state.departments[action.payload.targetDepartment],
dayData: {
...state.departments[action.payload.targetDepartment].dayData,
[action.payload.day]: {
...state.departments[action.payload.targetDepartment].dayData[action.payload.day],
[action.payload.targetField]: {
...action.payload.data,
isFetching: false,
receivedAt: new Date(),
didInvaldiate: false,
didCall: true
}
}
}
}
}
};
Is it better to move dayData to it's own reducer or does it make no difference?

My advice would be to normalize your state into a flat state.
You should take a look to: https://github.com/paularmstrong/normalizr
And see the video of Dan Abramov on egghead about normalizing redux state: https://egghead.io/lessons/javascript-redux-normalizing-api-responses-with-normalizr
This egghead lesson was one of the most important things I learned about how to manage redux state and I highly recommend to see it and read more about this matter.
Recently twitter released their mobile website with react and redux and there was a article dissecting their state, which might also be a interesting read: https://medium.com/statuscode/dissecting-twitters-redux-store-d7280b62c6b1#.2e55tu6wb

Your example of an immutable nested data update is correct. However, #Canastro is also correct - this is a good candidate for normalization.
I'd encourage you to read through Redux FAQ: Organizing State and Structuring Reducers in the Redux docs, as well as some of the articles in the Redux Techniques#Normalization section of my React/Redux links list.

Related

Confusion with the way Redux selector is used

I was learning Redux and came across the concept of Redux selector. I got curious what that was and found out that it is a function that encapsulates the logic of slice of store state so that we can reuse it. Here is the code:
function mapStateToProps(state) {
return {
incompleteTodos: state.todos.filter((todo) => {
return !todo.completed
});
}
}
Becomes
function mapStateToProps(state) {
return {
incompleteTodos: getIncompleteTodos(state)
};
}
But the question I wanted to ask is that Is it true that when we use selector like this incompleteTodos: getIncompleteTodos(state) apart from reusability we also get memoization by default. Thus, we do not need to use reselect library. Is that true?
Short answer your question is No. By default properties in mapStateToProps is calculated every time when the component is updated, but there is some other solutions:
Reselect library which you mention, it's official package of Redux team so you can trust it.
You can use Redux Toolkit package which is also an official library and out of the box it also has Reselect.
You can use Redux Hook - useSelector which by default behaves like memorized property, so i guess this is what you are interested, in terms of default memorization.

Redux: how can mutating state by creating a shallow copy cause problems in reducer?

Making a shallow copy of the state is listed in the Redux docs as one of the common mistakes when updating nested state:
function updateNestedState(state, action) {
// Problem: this only does a shallow copy!
let newState = { ...state }
// ERROR: nestedState is still the same object!
newState.nestedState.nestedField = action.data
return newState
}
I still don't get why this is a problem with Redux. Doesn't reducer in Redux work synchronously such that when the reducer returns, Redux will only take into account the returned new state and discard the old one?
Based on my discussion with Mark Erikson (Redux mantainer) on the related question's comment section, it won't cause problems with Redux, but it will break the libraries and toolings built around it (Redux DevTools, React-Redux, React, etc.) that rely on proper use of immutability. My highlights:
It's very likely that time-travel debugging and component re-rendering will break.
It's entirely possible for a reducer function to mutate its state, but we are not supposed to do any of those things.
Source: https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/#summarizing-redux-s-technical-requirements

Redux: Generic update action

I'm working with Redux and my state is a normalized one with a lot of different models. Now I was wondering myself if it was better to have specific actions like:
{type: CHANGE_MODEL_NAME, modelId, name}
vs
{type: UPDATE_MODEL, modelId, {name}}
I did a bit of searching and I found this question:
Is it ok to create generic redux update action
Now what I'm wondering is that no one is adressing the fact that having specific action types allow for different reducers to 'react' to an action in a cleaner way.
IE: I have a model that is copied from another model like so:
{
name: 'foo',
originalModel: id_0
}
It then becomes easier to react to specific actions in my reducer of copied models if I only want to react to the name change action.
Is it wrong for 2 reducers to react to the same actions? Is that why nobody adressed this issue in the original question?
Having multiple slice reducers respond to the same actions is absolutely an intended use case for Redux. I covered that background in my post The Tao of Redux, Part 1 - Implementation and Intent.
As for your specific question: I think it's entirely valid to have an update action for normalized data that contains the item type name and the item ID. In fact, I demonstrated this exact approach in my post Practical Redux, Part 7: Form Change Handling, Data Editing, and Feature Reducers.
Overall, Redux itself doesn't care what specific action types you have and how generic they are. You are encouraged to define whatever actions are appropriate for your app, and what level of "abstraction" they represent. It's very reasonable to make them a bit more generic - for example, I'd prefer UPDATE_USER_ATTRIBUTES instead of SET_USER_FIRST_NAME and SET_USER_LAST_NAME, but ultimately it's up to you.
This is perfectly valid. This pattern even has a name. "Applying a change set"
Your message becomes the following:
{type: APPLY_CHANGSET, data: {id: idOfThingToApplyTo, propOne: '1', propTwo: '2'}}
Your reducers can then look like this:
const propOneReducer = (value = 'default', {type, {data: {propOne}}) => {
return type === APPLY_CHANGSET && propOne !== undefined ? propOne : value;
}
This makes it a lot easier to add new properties (attributes) to your objects in your store. Adding a reducer, and sending the data from your react views to the actionCreator. In simple cases, you might not even need to change the actionCreator.
In these simple cases you can even build a reducer creator, basically creating the reducer for you.
Pro's
Less actions in the system
Simple sweet actionCreators
Not Pro's
Actions don't describe exactly what is happening. It's also harder to parse exactly what happens to the store after a actionCreator is invoked. This because the reducers now take the shape of the data into account.
Slightly more complex reducers

Redux - Use action object method in reducer instead of switch

I'm new to redux and looked at redux-actions or using switch statements in reducer, and though I'm not against using a switch statement, I'm wondering, isn't it easier to just use the call the action method?
Here's what I'm thinking
import actions from './actions'
const reducer = (state = {}, action) => {
if (actions[action.type]) return Object.assign({},
state, actions[action.type](action)
);
return state;
}
I've just tested this on my first reducer and action, and it works, but it seems quite obvious so I'm wondering why the switch type is the chosen way?
Switch statements are certainly the most common approach, but lookup tables are common as well. You can even use plain if/then conditions if you want. Ultimately, how you write your reducers is up to you.
FYI, this topic is covered in the Redux FAQ, in the FAQ: Reducers section. You might also want to read the new "Structuring Reducers" how-to section as well.
Some observations:
Don't refer to these external functions as "actions". They're not actions. They're actually reducers themselves.
Being reducers, you really ought to be passing the state object to them. Oftentimes, you'll want/need to utilise information contained in the current state, as well as information contained in the action object.
Otherwise, this seems like an appropriate approach.

Why doesn't Redux pass state to subscribed functions?

Why doesn't Redux just push the new state to listeners (as a parameter) like many callbacks do?
for (var i = 0; i < listeners.length; i++) {
listeners[i](currentState)
}
So we could...
store.subscribe(state => {
// ...just use it here...
})
...instead of having to call
store.subscribe(() => {
store.getState() // ?
})
Okay, it looks like this has been suggested numerous times in Redux's issue tracker on GitHub.
Here is what the devs have said about it:
#303 (Jul 27, 2016) "subscribe [is] a low level API." — gaearon, the project founder
#1514 (Mar 11) "In any case, having just the new state is not very useful. You’ll probably want the previous state too. And not just the previous state—probably a specific part you care about. At which point you might as well write your own helper to do this." — gaearon
#1832 (Jun 27) "The short version is that Redux just provides the simplest API possible."
And that's just a few of them. Tons of people have asked this question.
I would write a TL;DR here, but I don't feel like it. So please do read anyway. :-)

Resources