Immutable State Updates in React: Best Practices for Complex Objects

Got it — here’s your React useState Immutable Update Cheatsheet condensed into a single interview-friendly page:

React useState Immutable Update Cheatsheet
1. Rule #1 — Immutability
Never mutate the existing state object.

Always return a new reference so React knows to re-render.

2. Shallow Updates (One-Level Objects)
jsx
コピーする
編集する
const [user, setUser] = useState({ name: 'Alice', age: 25 });

setUser(prev => ({
  ...prev,
  name: 'Bob' // update one property
}));
3. Deep Updates (Nested Objects)
jsx
コピーする
編集する
const [person, setPerson] = useState({
  name: 'Niki',
  artwork: { title: 'Blue Nana', city: 'Hamburg' }
});

setPerson(prev => ({
  ...prev,
  artwork: { ...prev.artwork, city: 'New Delhi' }
}));
Repeat shallow-copy for each nested level you modify.

4. Easier Deep Updates with Immer
jsx
コピーする
編集する
import produce from 'immer';

setUser(prev =>
  produce(prev, draft => {
    draft.details.city = 'NewCity';
  })
);
Write like you’re mutating — Immer returns a new immutable object.

5. Why Use Functional Updates?
React updates state asynchronously.
setState(prev => ...) ensures you always work with the latest value.

jsx
コピーする
編集する
setCounter(prev => prev + 1);
6. Key Differences from Class setState
Class setState merges objects automatically.

useState replaces the whole state — you must manually merge.

7. Interview Pro Tips
Always spread (...) old state into the new one before overriding properties.

For arrays, use [...prev, newItem] or .map() for updates.

For very complex state, use useReducer or Immer.

Quick Summary Table

Situation	Example
Shallow object update	{ ...prev, key: value }
Nested object update	{ ...prev, nested: { ...prev.nested, key: value } }
Array add item	[...prev, newItem]
Array remove/filter item	prev.filter(item => item.id !== id)
Array update item	prev.map(item => item.id === id ? {...item, key: v} : item)
Complex deep updates	immer or useReducer