What is React Fiber and how is it an improvement over the previous approach?
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.