keepcalculator

06 Numbers and Powers

React State Updates: Queue to Committed UI

Card No. 06·61854 · Updated · Standard formula, shown below

React state updates from queued setter to committed UI happen in two distinct phases: the render phase (where your component function runs and produces new JSX) and the commit phase (where React updates the actual DOM). The setter function you call (like setCount) does not immediately change the state variable; it schedules an update, and React decides when to process it based on batching and priority.

How React Queues Setter Calls

When you call a setter, React adds the update to a queue associated with that state variable. The queue is not processed immediately. Instead, React waits until the current execution context (like an event handler, effect, or timeout) finishes. Then it processes the queue in the order the setters were called.

For example:

const [count, setCount] = useState(0);

function handleClick() {
  setCount(count + 1); // queued
  setCount(count + 1); // queued
}

Both setters use the same count value from the current render (0), so the final state is 1, not 2. If you want to update based on the previous queued value, use the functional form: setCount(prev => prev + 1).

Batching: Automatic Grouping of Updates

React batches multiple setter calls that happen in the same event handler, effect, or lifecycle method. This means only one re-render occurs, not one per setter. Since React 18, batching happens automatically for all updates, including inside promises, timeouts, and native event handlers.

Batching is a performance optimization. Without it, every setter would trigger a separate render, causing wasted work and potential flickering. The user sees only the final committed state.

From Render to Commit: The Two Phases

Once the queue is processed, React enters the render phase. It calls your component function to get the new JSX (a React element tree). React then compares this new tree with the previous one (a process called reconciliation) to determine what changed. This comparison happens in memory, not in the DOM.

After the render phase, React commits the changes to the DOM. The commit phase is synchronous and updates the actual browser DOM nodes. Only after this commit does the user see the updated UI. If a render throws an error, React discards the render and does not commit anything.

Common Misconceptions and Pitfalls

  • State changes immediately: No, the variable stays the same until the next render. Accessing it right after calling the setter gives the old value.
  • One setter = one render: Not always. Batching can group multiple setters into one render.
  • Reading state in a loop: If you call setCount(count + 1) in a loop, you will still get only one increment because each call uses the stale count.
  • Mutating objects directly: Changing an object property and then calling the setter with the same reference may not trigger a re-render because React compares references.

How to Force a Commit Immediately

Normally you do not need to force a commit. But in rare cases (like reading the DOM right after an update), you can use flushSync from react-dom. This forces React to flush the queued updates synchronously and commit before returning. Use it sparingly because it disables batching and can hurt performance.

import { flushSync } from 'react-dom';

flushSync(() => {
  setCount(5);
});
// DOM is updated now

Frequently Asked Questions

Why does my state not update immediately after calling setter?

React schedules the update and processes it after the current event handler finishes. The state variable only changes after the component re-renders. This is by design to avoid inconsistent UI and to allow batching.

What is the difference between render and commit in React?

The render phase is when React calls your component function and computes the new virtual DOM. The commit phase is when React applies those changes to the real DOM. The render can be interrupted (in concurrent mode), but the commit is synchronous and atomic.

How do I update state based on the previous state?

Use the functional form: setCount(prev => prev + 1). This ensures you are working with the latest queued value, not the stale value from the current render.

Does React always batch updates?

Since React 18, updates inside promises, timeouts, and native event handlers are batched automatically. In earlier versions, only React event handlers were batched. You can opt out of batching with flushSync if needed.

Why does my component render twice in development?

React’s Strict Mode intentionally double-invokes render functions in development to help find side effects. This does not happen in production builds.

Can I see the queued updates before commit?

No, the queue is internal. You can only observe the final state after commit. For debugging, use the React DevTools to inspect state and props.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →