Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

A React state setter queues an update and asks React to render again; it does not change the state value already captured by the JavaScript code currently running. React later calls the component with a new state snapshot, calculates the next UI, and commits any necessary changes to the screen.

Why state behaves like a snapshot

Each time React renders a function component, it gives that render a particular set of props and state values. The component’s JSX and the event handlers it creates use those values. State is maintained by React outside the component function; a render receives a snapshot of it.

That means a state variable is not a mutable local variable that a setter rewrites in place. Calling setCount(count + 1) requests an update, but count inside the current handler remains the value from the render that created the handler. The same is true of asynchronous callbacks created during that render: they retain the values they captured.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What happens after a setter is called

React describes a screen update as three steps: trigger, render, and commit. A state setter triggers a render. React calls the relevant component functions to calculate what should appear, following the returned component tree as needed. It then commits the resulting changes to the screen.

  • Trigger: A setter requests an update.
  • Render: React calls components to calculate the next UI from their props and state.
  • Commit: React applies the necessary changes to the screen.

Rendering is the calculation of the next UI; it is not itself a screen update. A render does not mean every DOM node changes, and the setter does not alter the screen at the instant it is called. See React’s Render and Commit guide for the full process.

Why logging immediately after a setter shows the old value

In this handler, the log uses the current render’s snapshot:

function handleClick() {
  setCount(count + 1);
  console.log(count); // The value from this render
}

If the current value of count is 0, the log prints 0, even though the update requests a render with the next value. React’s State as a Snapshot guide explains why an update does not change values in code that is already executing.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

If other code in the handler needs the next value immediately, calculate it yourself and use that local value for the immediate work:

const nextCount = count + 1;
setCount(nextCount);
console.log(nextCount);

This does not make React’s state update synchronous; it simply gives the handler a local value it can use before the next render.

Why multiple updates may not add up as expected

React queues updates and processes them after the current event handler finishes. This batching lets React handle related changes together rather than showing an intermediate interface after each setter call.

Replacement values use the same snapshot

Three calls like these all calculate from the same number captured by the handler:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);

If that snapshot is 0, each call requests the replacement value 1. They do not successively read the result of the preceding call.

Updater functions build on queued results

When each update depends on the previous value, pass React an updater function:

setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);

React applies these functions in order during the next render. Each receives the value returned by the one before it, so three queued increments increase the value by three.

Updater functions must be pure: calculate and return the next state without causing side effects or setting state from inside the updater. React may call an updater twice in development when Strict Mode is enabled and discard one result to help detect impure logic. See Queueing a Series of State Updates for examples and details.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When React may not show an update

A setter call does not guarantee a visible change. React’s useState reference says React can ignore an update when the next value is equal to the current value according to Object.is. For example, setting a number to its existing value does not produce a different state snapshot to display.

How this compares with class-component setState

Function components use setters such as setCount; class components use this.setState. React describes class setState as a request rather than an immediate command. Its queued updater functions calculate next state from the prior state, so the same distinction between requesting an update and immediately changing the currently executing code applies. See the Component reference.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.