How does useState work? Why does logging state right after calling the setter show the old value, and when should you use the updater function form setCount(c => c + 1)?
Show the explanation
Model answer. const [value, setValue] = useState(initial) returns the current value and a setter. Calling the setter schedules a re-render; on the next render, useState returns the new value.
Within the current render, value is a constant snapshot: the setter does not change it.
function Counter() {
const [count, setCount] = useState(0);
function addThree() {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
console.log(count); // still 0: the snapshot from this render
} // result after re-render: 1, not 3
}All three calls computed 0 + 1. Use the updater form when the new state depends on the previous state; React queues the functions and applies them in order:
setCount(c => c + 1); setCount(c => c + 1); setCount(c => c + 1); // 3Other rules:
- Treat state as immutable: create new objects and arrays (
setUser({ ...user, name })) rather than mutating, or React may not re-render. - Updates inside one event are batched into one render.
- For an expensive initial value, pass a function:
useState(() => loadFromStorage()).
Original UniCircle question. Last reviewed 22 Oct 2026.
