Redux requires that one always returns new state from reducers. For example, I have the following state:
let initialState = {
prop: 3,
internalReferenceProp: {a:3}
}
And the reducer that modifies internalReferenceProp
. This reducer can be implemented to change only state
object reference or both state
and internalProperty
:
function(state=initialState, action) {
// changing only state reference
let newState = Object.assign({}, state);
newState.internalReferenceProp.a = 7;
return newState;
// changing both state and internalReferenceProp reference
return Object.assign({}, state, {internalReferenceProp: {a:7}})
}
As I've been told first approach is not correct, so my question is what's the reasoning behind requirement to also change internal references? I understand that I should change state
reference because it allows for an easy comparison to detect whether state
changed, but why change internal references?
The first one is clearly not correct because Object.assign
does a shallow copy, not a deep one.
// changing only state reference
let newState = Object.assign({}, state);
newState === state // false
newState.internalReferenceProp === state.internalReferenceProp // true
state.internalReferenceProp.a // 3
newState.internalReferenceProp.a = 7 // 7
state.internalReferenceProp.a // 7
You can see that this way, if we change something in newState
it gets changed in state
as well. This will make the change undetectable if a component is only interested in internalReferenceProp
. This is also called a "side-effect" and is a bad practice.
In short, if your input (state
in this case) changes in any way, it's called a side-effect and is wrong in redux.
Here's an example of why this is bad:
let data = getData(); // from redux
return (
<ChildComponent someProp={data.internalReferenceProp} />
);
If we use the version with side-effects, ChildComponent
will never re-render because its props didn't change. oldData.internalReferenceProp === newData.internalReferenceProp
.