EasyHooks📖 Theory Question

Explain useState — batching, functional updates, and lazy initialization.

💡

Hint

State updates are batched; use functional form for updates based on previous state; pass a function to useState for expensive initial computation

Full Answer

const [state, setState] = useState(initialValue);

Functional updates — use when next state depends on current state:

// ❌ Potentially stale closure
setCount(count + 1);
setCount(count + 1); // both read the same stale 'count'

// ✅ Always gets the latest value
setCount(c => c + 1);
setCount(c => c + 1); // correctly increments twice

Batching — React 18 batches all state updates (even in setTimeout, fetch callbacks) into a single re-render:

// React 18: both updates batched into ONE re-render
setTimeout(() => {
  setCount(c => c + 1);
  setName('Alice');
}, 0);

Lazy initialization — pass a function to avoid re-running expensive setup on every render:

// ❌ computeExpensive() runs every render (result discarded after mount)
const [state, setState] = useState(computeExpensive());

// ✅ Only runs on mount
const [state, setState] = useState(() => computeExpensive());
💡 State updates are asynchronous — you won't see the new value immediately after calling setState. React schedules a re-render; the new value appears in the next render's closure.

Practice this in a timed sprint →

5 free questions, no signup required

⚡ Start Sprint