Skip to main content

Mutating state in a reducer

Short answer

You cannot mutate (change directly) state in 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:

  1. It does not change the input data (state).
  2. It returns a new object describing the new state.

Example of a correct reducer

javascript
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

javascript
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.

javascript
oldState === newState // if true -> we do not re-render

If 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:

OperationMutationImmutable
Add an elementarray.push(x)[...array, x]
Remove an elementarray.splice(1,1)array.filter((_, i) => i !== 1)
Change a propertyobj.key = value{ ...obj, key: value }
Change a nested objectstate.user.name = 'Tim'{ ...state, user: { ...state.user, name: 'Tim' } }

Summary

ReasonWhy you cannot mutate
Redux compares by referenceIt will not see the change
Time travel in DevToolsOld states would be lost
TestingIt becomes unpredictable
React optimizationsWill not work correctly
The pure function principleDeterminism is broken

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.