Why must React state be updated immutably?
Take a moment.
Say your answer out loud or write it down first — retrieval is what makes it stick. Reveal when you're ready.
Short answer
React detects changes by reference comparison (Object.is). Mutating in place keeps the same reference, so React sees 'no change', skips re-rendering, and memoization breaks. Always create new objects/arrays with spread or structured updates.
Detailed explanation
React's rendering model assumes state transitions produce a new snapshot: setState receives a different reference and re-renders accordingly. Mutating state.push(item) leaves the reference identical — Object.is(oldState, newState) is true — so React may skip the update entirely, and memoized components or useMemo comparisons see nothing changed either. Immutable updates also enable cheap history (undo/redo), time-travel debugging, and predictable diffs since old snapshots never change underneath you. Patterns: spread for top-level ({ ...user, name }), map/filter for arrays, targeted spread for nested paths ({ ...form, address: { ...form.address, city } }). For deep trees, libraries like Immer let you write mutations that produce immutable results. Note: only the path that changed needs copying — shallow-copy along the changed branch.
Official docs:React docs: Updating Objects in State
Example
// ❌ mutation — same reference
items.push(newItem);
setItems(items);
user.address.city = 'NYC';
// ✅ immutable updates
setItems([...items, newItem]);
setItems(items.filter(i => i.id !== id));
setUser({ ...user, address: { ...user.address, city: 'NYC' } });Interview tip
Anchor everything to Object.is reference comparison — one sentence explains why mutation silently fails — then show nested-update syntax fluently.
Common mistakes
- Sorting/reversing state arrays in place (sort mutates!).
- Deep-cloning entire state when only one branch changed.