Frontend Development 8 min read

Understanding State Updates and Rendering Behavior in React 18 Concurrent Mode

This article explains how React 18's concurrent mode changes state calculation and rendering by introducing update priorities, showing how multiple state updates are batched, how low‑priority updates can be skipped, and why the new scheduler reduces unnecessary renders while preserving final results.

IT Services Circle
IT Services Circle
IT Services Circle
Understanding State Updates and Rendering Behavior in React 18 Concurrent Mode

React 18 has entered the release‑candidate (RC) stage, just one step away from the final version.

Version 18 adds many features, but this article focuses on a detail that makes the new version superior to the old one: the number of component renders can be reduced.

In React 18, a component may render fewer times.

Where Does State Come From

Consider the following component:

function App() {
  const [num, update] = useState(0);
  // ... omitted
}

When the App component renders, it executes useState and receives the latest value of num . In other words, the component must render to know the current state.

Now look at the code that triggers updates:

const [num, update] = useState(0);
const onClick = () => {
  update(100);
  update(num => num + 1);
  update(num => num * 3);
};

When onClick runs, it causes the App component to render, which in turn runs useState . Inside useState , the state is calculated in the following order:

update(100) changes num to 100 .

update(num => num + 1) changes num to 100 + 1 = 101 .

update(num => num * 3) changes num to 101 * 3 = 303 .

Thus, after the render, num equals 303 .

The calculation requires first collecting all triggered updates and then applying them uniformly inside useState .

baseState -> u0 -> u1 -> u2 = newState

Changes Brought by Concurrent

Concurrent mode introduces the concept of priority , which affects state calculation. Updates triggered in different contexts have different priorities (e.g., updates from an onClick callback have higher priority than those from a useEffect callback).

If an update has a lower priority, it may be skipped during a render.

Assume in the previous example that u1 has low priority and is skipped. The state formula becomes:

// u1 is skipped
baseState -> u0 -> u2 = newState

Consequently, the intermediate result would be 100 * 3 = 300 , which is incorrect. In concurrent React, the state‑calculation logic becomes more complex and may involve multiple passes.

When a low‑priority update is skipped, the next calculation resumes from that skipped update, preserving it and all subsequent updates for the next render.

In the example, after the first render the state is 100 . The next render processes u1 (the +1 update) and then u2 (the *3 update), yielding the final 303 . The synchronous React version achieves the same final result with a single render, while the concurrent version needs two renders (intermediate 300 and final 303 ).

Differences Between Old and New Concurrent

In the older concurrent implementation, priority is represented by an expirationTime timestamp. An update is skipped if its expiration time is less than the render's expiration time:

// if update priority is lower than render priority
if (updateExpirationTime < renderExpirationTime) {
  // ...skip
} else {
  // ...process
}

Thus, any low‑priority update causes an extra render.

In the newer implementation, priority is stored as a 31‑bit binary lane mask. For example:

const renderLanes = 0b0101;
u1.lane = 0b0001;
u2.lane = 0b0010;

The function that checks priority is:

function isSubsetOfLanes(set, subset) {
  return (set & subset) === subset;
}

Here u1.lane is included in renderLanes (high enough priority), while u2.lane is not (low priority) and will be skipped. Skipped updates have their lane reset to 0b0000 , which is always a subset of any render lane, guaranteeing they will be processed in a later render. Consequently, the new concurrent scheduler limits the number of extra renders to at most two.

Summary

Compared with the older concurrent implementation, the new React 18 concurrent mode reduces the number of renders required to reach the final state, leading to smoother user experience and fewer visible intermediate states.

renderingState ManagementReActConcurrent ModeReact18
IT Services Circle
Written by

IT Services Circle

Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.