What happens when you call a useState setter?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
Calling the setter does not change your local variable. It schedules a re-render. React stores the new value, and on the next render the hook returns it.
const [count, setCount] = useState(0);
function onClick() {
setCount(1);
console.log(count); // still 0 — count is a const from this render
}
count is a snapshot belonging to the render it was read in. Nothing can retroactively change it.
The sequence
- React compares the new value with the current one using
Object.is. If they match, it may skip the re-render entirely. - Otherwise the update is queued on that hook.
- Updates are batched: every setter called in the same event handler, effect, or promise callback produces one re-render, not one each.
- React re-runs the component function, and
useStatereturns the new value. - It diffs the returned elements against the previous tree and applies only the changes to the DOM.
- Effects whose dependencies changed run after the browser has painted.
Why the updater function matters
Because the setter reads a stale snapshot, two increments in a row both start from the same value:
setCount(count + 1);
setCount(count + 1); // both compute 0 + 1 -> ends at 1
setCount(c => c + 1);
setCount(c => c + 1); // React applies them in order -> ends at 2
Use the function form whenever the next value depends on the previous one.
Two things that surprise people
Objects must be replaced, not mutated. Object.is compares references, so user.name = 'x'; setUser(user) changes nothing — React sees the same object and bails out. Write setUser({ ...user, name: 'x' }).
The bail-out is not always immediate. If you set the same value, React may still re-render the component once before deciding nothing changed. It will not re-render the children, so this is rarely a problem, but do not rely on "same value means no render".
Calling it during render
Calling a setter unconditionally in the render body is an infinite loop, and React throws "Too many re-renders". The one legitimate case is a guarded update that derives state from props, and even there the docs prefer computing the value directly or using a key to reset.
