Quiz

What is React Fiber and how is it an improvement over the previous approach?

Topics
React

TL;DR

React Fiber is a complete rewrite of React's reconciliation algorithm, introduced in React 16. It improves the rendering process by breaking down rendering work into smaller units, allowing React to pause and resume work, which makes the UI more responsive. This approach enables features like time slicing and suspense, which were not possible with the previous stack-based algorithm.


What is React Fiber and how is it an improvement over the previous approach?

Introduction to React Fiber

React Fiber is a re-implementation of React's core algorithm for rendering and reconciliation. It was introduced in React 16 to address limitations in the previous stack-based algorithm. The primary goal of Fiber is to enable incremental rendering of the virtual DOM, which allows React to split rendering work into chunks and spread it out over multiple frames.

Key improvements over the previous approach

Incremental rendering

The previous stack-based algorithm processed updates in a single, synchronous pass, which could lead to performance issues, especially with complex UIs. React Fiber breaks down rendering work into smaller units called "fibers", allowing React to pause and resume work. This makes the UI more responsive and prevents blocking the main thread for long periods.

Time slicing

Time slicing is the chunking mechanism that lets Fiber split rendering work into small units and yield back to the browser between them. Fiber tracks how much time has been spent on a render pass and pauses if it would otherwise block the main thread, then resumes work on the next idle frame. This keeps input, scroll, and paint responsive even during a large render.

Prioritization with lanes and transitions

Separate from time slicing is the question of which work to do first. In React 18+, Fiber uses a "lanes" model to assign priorities to updates. Urgent updates (such as input or click handlers) run on high-priority lanes, while updates wrapped in startTransition or coming from useDeferredValue run on lower-priority lanes that can be interrupted by more urgent work.

Double-buffered work-in-progress trees

Fiber maintains two trees: the "current" tree that reflects what's on screen, and a "work-in-progress" tree that React builds in memory. Because the new tree is constructed off-screen, React can pause, throw away, or restart the work-in-progress tree without ever showing a half-rendered UI to the user. The two trees swap atomically once the commit phase completes.

Opt-in concurrent rendering

Concurrent rendering features (transitions, Suspense for data, automatic batching across async boundaries, and so on) are opt-in via the new root API. Calling createRoot(container).render(<App />) enables concurrent features for the tree; the legacy ReactDOM.render API has been removed in React 19.

Error boundaries

Error boundaries let components catch render-time errors in their subtree and show a fallback UI instead of crashing the whole app. They were introduced as a public React 16 API alongside Fiber, but they're conceptually independent of the Fiber scheduler — error boundaries are about error containment, not about how work is scheduled.

Owner stacks (React 19.1)

React 19.1 added improved "owner stacks" in development, which give clearer component-level stack traces for errors and warnings by walking the Fiber tree's owner relationships rather than relying purely on JavaScript call stacks. This makes it much easier to track down where a bad prop or thrown error originated.

Improved support for animations

Fiber's incremental rendering and time slicing capabilities make it easier to implement smooth animations and transitions. React can now prioritize animation frames and ensure that they are rendered in a timely manner, leading to a better user experience.

Code example

Here's a simple example showing how to opt into Fiber's concurrent rendering for a large list:

import { useState, useTransition } from 'react';
function BigList() {
const [items, setItems] = useState([]);
const [isPending, startTransition] = useTransition();
function loadItems() {
startTransition(() => {
setItems(Array.from({ length: 10000 }, (_, i) => i));
});
}
return (
<div>
<button onClick={loadItems}>Load items</button>
{isPending && <p>Loading…</p>}
{items.map((item) => (
<div key={item}>{item}</div>
))}
</div>
);
}

A purely synchronous render of 10,000 items will still block the main thread in Fiber — Fiber doesn't magically time-slice every render. It's the concurrent-rendering APIs (startTransition, useDeferredValue, Suspense) that let Fiber treat the work as interruptible. By marking the state update as a transition, React can render the list on a low-priority lane and yield to user input in between, keeping the UI responsive.

Further reading

Edit on GitHub