Difficulty: Advanced
What is React Fiber? Why was it introduced and what does it enable?
React Fiber is one of those topics that separates someone who uses React from someone who truly understands React. Let me explain it in a way that actually makes sense.
To understand Fiber, you first need to understand the problem it solved. Before React 16, React used what is called the Stack Reconciler. When React needed to update the UI -- say, a big state change that affects hundreds of components -- it would start at the top of the component tree and work its way down, diffing every component, synchronously, in one giant uninterruptible operation. Think of it like reading an entire 500-page book in one sitting without being allowed to stop. If this reconciliation took 200 milliseconds, the browser's main thread was completely blocked for 200 milliseconds. No animations could run, no user input could be processed, nothing. The UI would literally freeze. Users would click a button, type in an input, and nothing would happen until React finished its work. This is what developers called "jank."
The Fiber rewrite, which shipped in React 16, fundamentally changed this. Instead of one big uninterruptible blob of work, Fiber breaks the rendering work into small units called fibers, and processes them one at a time. After each unit of work, Fiber checks: is there something more important I should be doing? Did the user type something? Is there an animation frame I need to handle? If yes, Fiber pauses the rendering work, handles the urgent thing, and then comes back to where it left off. It is like reading that 500-page book one chapter at a time, checking your phone between chapters.
So what exactly IS a fiber? It is just a plain JavaScript object. Every component instance, every DOM element in your React tree has a corresponding fiber node. These fibers form a linked list tree structure using three pointers: child (first child), sibling (next sibling), and return (parent). This linked list structure is what makes pausability possible. The old Stack Reconciler used the actual JavaScript call stack (recursive function calls), and you cannot pause the call stack -- once a function starts, it runs to completion. With a linked list, React can stop at any fiber node, save its position, do something else, and come back.
Fiber also introduced the concept of two phases in rendering. The render phase (also called reconciliation) is where React walks through the fiber tree, computes what changed, and builds a list of effects (DOM mutations needed). This phase IS interruptible -- React can pause, abort, or restart it. The commit phase is where React actually applies those changes to the DOM. This phase is NOT interruptible because you cannot have a half-updated DOM -- that would look broken to the user. The commit phase runs synchronously and quickly.
Another key concept is double buffering. React maintains two fiber trees: the current tree (what is currently on screen) and the work-in-progress tree (the new version being computed). When the work-in-progress tree is fully computed and committed, it becomes the new current tree. This is similar to how video games render the next frame in an off-screen buffer and then swap it in all at once.
Fiber also introduced priority levels. Not all updates are created equal. A user typing in an input field (UserBlockingPriority) should be handled faster than a data fetch response updating a chart (NormalPriority), which should be handled faster than an analytics event (IdlePriority). Fiber's scheduler assigns priorities to updates and processes them in the right order, interrupting low-priority work to handle high-priority work.
Here is why this all matters practically: Fiber is the foundation that makes every modern React feature possible. Suspense works because Fiber can pause rendering a component while it waits for async data. Error Boundaries work because Fiber can catch errors during the render phase and recover gracefully. useTransition and useDeferredValue work because Fiber can interrupt low-priority rendering work. Automatic batching works because Fiber can schedule multiple state updates into a single render pass. Concurrent rendering in React 18 is literally Fiber doing what it was designed for.
A common interview mistake is treating Fiber as something magical or overly complex. At its core, it is just a data structure change: from recursive call stack to linked list. That one change enabled pausability, which enabled prioritization, which enabled concurrent rendering. The genius is in the simplicity of the insight, not in the complexity of the implementation.
You will probably never interact with Fiber directly in your application code. But understanding it helps you reason about why React behaves the way it does: why renders can be interrupted, why effects might run more than once in StrictMode, why the commit phase is always synchronous, and why concurrent features require createRoot.
// Simplified conceptual model of Fiber work loop
// NOT actual React source code
// Each component has a fiber node:
const fiberNode = {
type: MyComponent,
key: null,
stateNode: componentInstance,
return: parentFiber, // parent
child: firstChildFiber, // first child
sibling: nextFiber, // next sibling
pendingProps: {},
memoizedProps: {},
memoizedState: null,
effectTag: 'UPDATE',
alternate: currentFiber, // double buffering
};
// The work loop processes one fiber at a time
function workLoop(deadline) {
let shouldYield = false;
while (currentFiber && !shouldYield) {
currentFiber = performUnitOfWork(currentFiber);
shouldYield = deadline.timeRemaining() < 1; // yield if time is up
}
// Schedule remaining work
if (currentFiber) requestIdleCallback(workLoop);
else commitRoot(); // Commit phase: apply all DOM changes at once
}
// The commit phase is synchronous and cannot be interrupted
// The render phase (building the fiber tree) CAN be interrupted
Fiber uses a linked list instead of the call stack, making it possible to pause and resume work. The render phase is interruptible; the commit phase is not.
// Fiber enables these React 18 features:
// 1. Automatic Batching
setTimeout(() => {
setCount(c => c + 1); // Was 2 renders in React 17
setFlag(f => !f); // Now 1 render in React 18 (Fiber schedules them)
});
// 2. Transitions (non-urgent work can be interrupted)
const [isPending, startTransition] = useTransition();
startTransition(() => {
setHeavyState(newValue); // Can be interrupted for urgent updates
});
// 3. Suspense (Fiber coordinates async component loading)
<Suspense fallback={<Spinner />}>
<LazyComponent />
</Suspense>
// 4. Error Boundaries (Fiber makes catching component errors possible)
<ErrorBoundary>
<MightThrow />
</ErrorBoundary>
// Priority levels (simplified)
const priorities = [
'ImmediatePriority', // Synchronous, cannot be interrupted
'UserBlockingPriority', // User interactions - must respond quickly
'NormalPriority', // Default: data fetching, renders
'LowPriority', // Transitions, background work
'IdlePriority', // Work that can wait indefinitely
];
Fiber's work scheduling enables all modern React features. Priority levels let React interrupt low-priority work to handle user interactions immediately.
Fiber, Reconciliation, Work Loop, Priority, Concurrent Mode