useState: State Management

Medium

Most state bugs are architecture bugs: duplicated source of truth, incorrect ownership, and mutation patterns that break referential assumptions.

Quick Decision Guide

useState gives local state with snapshot semantics and scheduled updates.

- Reads are from current render snapshot - Writes schedule future renders - Functional updates avoid stale closure bugs

Interview signal: Discuss state ownership and update fan-out, not just setter syntax.

State Ownership Mental Model

🔥 Insight

State location defines performance boundaries.

🧠 Mental Model

Place state near consumers
Lift only when multiple branches need coordinated reads/writes
Derive whenever possible instead of duplicating data

Update Semantics and Edge Cases

Pattern 1: Functional Updates

Use when state depends on previous state:

// ❌ WRONG - Stale closure
const [count, setCount] = useState(0);
const increment = () => {
  setCount(count + 1); // May use stale value
  setCount(count + 1); // Still uses stale value
};

// ✅ CORRECT - Functional update
const increment = () => {
  setCount(prev => prev + 1);
  setCount(prev => prev + 1); // Uses latest value
};

Pattern 2: Object State

Update objects immutably:

const [user, setUser] = useState({ name: '', age: 0 });

// ✅ CORRECT - Immutable update
setUser(prev => ({ ...prev, name: 'John' }));

Edge Cases

Lazy initialization for expensive defaults: useState(() => expensiveInit())
Object/array updates must create new references
Derived values belong in render/useMemo, not duplicated state

Rules of Hooks (and why)

Call hooks at the top level of React components or custom hooks.
Do not call hooks inside conditions, loops, or nested functions.
Only call hooks from React function components or other custom hooks.

These rules follow from React's render model:

React relies on consistent hook call order across renders.
Hook identity is tied to position in the render sequence.
Conditional or reordered hook calls can misassociate state/effects and produce incorrect behavior.

Trade-offs and Interview Takeaway

Trade-offs

Local state is easy to reason about
Over-lifting state increases rerender surface area
Too much derived duplication increases inconsistency risk

🎯 Interview Takeaway

Strong answer: choose state owner intentionally, prefer derivation, and use functional updates when next state depends on previous state.

Key Takeaways

1useState is about ownership and boundaries, not just mutability.
2Functional updates protect against stale snapshot bugs.
3State placement often dominates UI performance outcomes.
4Avoid duplicated derived state.