Question presented to candidate:
"If you call three setters in one event handler, how many times does the component render? And does that change inside a setTimeout?"
What a strong answer should cover:
- Batching groups multiple state updates into a single re-render, so the UI never shows a half-applied intermediate state.
- Automatic batching since React 18 applies everywhere — event handlers,
setTimeout, promises, native event listeners. Before 18 it only applied inside React event handlers. - That was one of the more visible behavioural changes in React 18, and a common source of "this used to render twice" surprises.
- State updates are asynchronous in the sense that the variable does not change until the next render — reading it immediately after a setter gives the old value.
- The functional updater is how you compose several updates to the same value:
setN(n => n + 1)three times increments by three, wheresetN(n + 1)three times increments by one. flushSyncopts out, forcing a synchronous render — an escape hatch for measuring the DOM between updates, at the cost of an extra render and lost batching.- Why it exists: fewer renders, and no intermediate frames where two related pieces of state disagree.
Clarifying questions expected:
- "Which React version?" — the answer genuinely differs before and after 18.
- "Are the updates to the same value or different ones?" — that decides whether a functional updater is needed.
Code / implementation expected: Yes — updates in a handler, in a timeout, and with a functional updater versus a stale read.