Mutating state in a reducer
Short answer
You cannot mutate (change directly)
statein a reducer, because Redux (and React) need to see that the state has changed, and that is only possible by creating a new object.
In detail
A reducer must be a pure function, which means:
- It does not change the input data (state).
- It returns a new object describing the new state.
Example of a correct reducer
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 } // create a new object
default:
return state
}
}Example with mutation
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT':
state.count++ // mutates the object
return state // returns the same object
default:
return state
}
}The problem: Redux (and React) will not understand that the state has changed,
because the reference to the object has not changed - state remains the same object in memory.
Why this matters
1. Redux compares states by reference
Redux (and React through useSelector) use a shallow comparison (===) to understand whether the state has changed.
oldState === newState // if true -> we do not re-renderIf you mutated the object, the reference stays the same -> Redux thinks nothing has changed -> the component does not update.
2. Immutability enables "time travel"
Redux DevTools can "rewind" state forward and backward, because every state is stored as a new version of the object.
If reducers mutated state, old states would simply be destroyed.
3. Simple testing
Pure functions are easy to test: the same input data -> always the same result. If you mutate state, the result can depend on the previous call.
4. Optimizing React components
Many optimizations (for example, React.memo, useSelector, PureComponent)
are based on reference comparison (===), not deep comparison.
Immutability is what makes this possible.
How to avoid mutating state
Use immutable methods:
| Operation | Mutation | Immutable |
|---|---|---|
| Add an element | array.push(x) | [...array, x] |
| Remove an element | array.splice(1,1) | array.filter((_, i) => i !== 1) |
| Change a property | obj.key = value | { ...obj, key: value } |
| Change a nested object | state.user.name = 'Tim' | { ...state, user: { ...state.user, name: 'Tim' } } |
Summary
| Reason | Why you cannot mutate |
|---|---|
| Redux compares by reference | It will not see the change |
| Time travel in DevTools | Old states would be lost |
| Testing | It becomes unpredictable |
| React optimizations | Will not work correctly |
| The pure function principle | Determinism is broken |
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.