How React’s Runtime Optimizations Evolved from 15 to 18 – A Deep Technical Dive
This article walks through the evolution of React’s runtime architecture from version 15 to 18, explaining key concepts such as Fiber, Scheduler, priority lanes, concurrent mode, and new APIs like startTransition and useDeferredValue, while providing concrete code examples and visual diagrams.
Design Strategies of Major JS Frameworks
React follows a runtime‑centric approach: when data changes it creates a new virtual DOM, computes the minimal set of changes with a diff algorithm, and applies them during runtime. In contrast, Svelte compiles templates ahead of time into native DOM operations, while Vue balances both by keeping a virtual DOM but performing many optimizations during compilation.
What Is Compile‑Time Optimization?
Vue’s template syntax (e.g., v‑if, v‑for) is limited and enumerable, allowing the compiler to pre‑compute many static aspects and generate more efficient code. Vue 3.0’s compiler can skip diffing static nodes, reducing unnecessary tree traversals.
Runtime Focus in React
React’s early versions (15) performed recursive, synchronous updates. The setState calls were synchronous, but React batched them to reduce renders. However, deep trees could exceed the 16.6 ms frame budget, causing jank.
class Example extends React.Component {
constructor() {
super();
this.state = { val: 0 };
}
componentDidMount() {
this.setState({ val: this.state.val + 1 });
console.log(this.state.val);
this.setState({ val: this.state.val + 1 });
console.log(this.state.val);
setTimeout(() => {
this.setState({ val: this.state.val + 1 });
console.log(this.state.val);
this.setState({ val: this.state.val + 1 });
console.log(this.state.val);
}, 0);
}
render() { return null; }
}In React 15 the printed order was 0,0,2,3, showing that setState is synchronous but its updates are batched.
Key Functions
_processPendingStatemerges pending state queues into a single state object. batchedUpdates wraps a function to batch state updates; it is synchronous, so it cannot batch asynchronous callbacks.
React 16 – Introducing Fiber and Concurrent Mode
React 16 added a Scheduler, a new Reconciler based on the Fiber data structure, and the concept of Concurrent Mode, which makes rendering interruptible and priority‑aware.
Fiber Node Example
function FiberNode(tag, pendingProps, key, mode) {
this.tag = tag;
this.key = key;
this.elementType = null;
this.type = null;
this.stateNode = null;
this.return = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
this.pendingProps = pendingProps;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
this.mode = mode;
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
this.lanes = NoLanes;
this.childLanes = NoLanes;
this.alternate = null;
}React now maintains two Fiber trees (current and work‑in‑progress) and switches pointers when an update is committed, enabling interruption.
Scheduler and Priority
The Scheduler stores ready tasks in a min‑heap ordered by expiration time. Priority levels include Immediate, UserBlocking, Normal, Low, and Idle. The Scheduler picks the task with the smallest expiration time (highest priority) and runs it until shouldYield() indicates the frame time is exhausted.
function workLoopConcurrent() {
while (workInProgress !== null && !shouldYield()) {
performUnitOfWork(workInProgress);
}
}When a task exceeds the frame budget, the Scheduler yields control back to the browser, allowing layout and paint to happen before resuming.
React 17 – Stabilizing Concurrent Mode and Multi‑Version Coexistence
React 17 moved event delegation from the document level to the root container, allowing multiple React versions to coexist on the same page without event conflicts.
The version also introduced the Lanes system, replacing the older expirationTime with bit‑field lanes for finer‑grained priority handling.
React 18 – Flexible Concurrent Rendering
React 18 ships with the new createRoot API that enables concurrent rendering by default. It also adds several developer‑friendly APIs:
startTransition – marks state updates as low‑priority transitions.
useTransition – provides an isPending flag to show loading UI.
useDeferredValue – defers rendering of a value until the browser is idle.
SSR now supports <Suspense> with fallback streaming.
startTransition Example
import { startTransition } from 'react';
// Urgent update – show typed text immediately
setInputValue(input);
// Transition – low‑priority update
startTransition(() => {
setSearchQuery(input);
});Updates inside startTransition can be interrupted by higher‑priority events, preventing UI jank.
useDeferredValue Example
const [deferredText] = useDeferredValue(text, { timeoutMs: 2000 });The deferred value is rendered with lower priority, automatically falling back to the immediate value if the render is fast.
SSR Suspense Support
When rendering on the server, React streams the fallback UI first and replaces it with the actual component once it resolves, enabling progressive hydration.
<Layout>
<Article />
<Suspense fallback={<Spinner />}>
<Comments />
</Suspense>
</Layout>Conclusion and Further Reading
Reading the React source code directly can be daunting. It is recommended to first study high‑level architecture overviews (e.g., the “React Technical Deep Dive” and “Illustrated React Source” series) before diving into specific modules such as Fiber, Scheduler, or Concurrent Mode.
React Technical Deep Dive: https://react.iamkasong.com/
Illustrated React Source: https://github.com/7kms/react-illustration-series
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ByteFE
Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
