Fiber Architecture — Complete Guide
In this tutorial, you will learn about Fiber Architecture. We cover key concepts, practical examples, and best practices to help you master this topic.
Fiber is React's reimplementation of the reconciliation engine that enables incremental rendering, work prioritization, and concurrency without blocking the main thread.
What You'll Learn
- What Fiber is and why React replaced the stack reconciler
- How Fiber enables incremental rendering
- How work prioritization works in Fiber
- How Fiber handles interruptions and resumption
Why It Matters
The stack reconciler blocked the main thread during rendering, causing jank in animations and input handling. Fiber fixes this by breaking work into units that can be paused and resumed.
flowchart TD
A[Fiber Reconciliation] --> B[Begin Work Phase]
B --> C{Time slice remaining?}
C -->|Yes| D[Process next fiber node]
C -->|No| E[Yield to browser]
E --> F{More work?}
F -->|Yes| B
F -->|No| G[Complete Phase]
G --> H[Commit Phase]
H --> I[DOM mutations applied]
What Is Fiber
Fiber is a Unit of Work in React's reconciliation. Each fiber node corresponds to a component instance or DOM element.
// Simplified fiber node structure
class FiberNode {
constructor(tag, pendingProps, key) {
this.tag = tag; // Component type (Function, Class, Host, etc.)
this.key = key; // Unique identifier
this.type = null; // The component function or element type
this.stateNode = null; // Reference to the real DOM node or component instance
// Tree structure
this.return = null; // Parent fiber
this.child = null; // First child fiber
this.sibling = null; // Next sibling fiber
// Work-related
this.pendingProps = pendingProps; // New props to process
this.memoizedProps = null; // Props from previous render
this.memoizedState = null; // State from previous render
// Effects
this.effectTag = null; // Placement, Update, Deletion, etc.
this.nextEffect = null; // Next fiber in effects list
// Priority
this.lanes = NoLanes; // Which updates this fiber is part of
this.childLanes = NoLanes; // Which updates children are part of
}
}
// Fiber creates a linked list tree (not recursive)
// This allows walking the tree iteratively instead of recursively
// Recursive calls cannot be interrupted. Linked list traversal can.
From Stack Reconciler to Fiber
The stack reconciler used recursive calls that could not be interrupted. Fiber uses a Linked List that can be paused.
// Stack reconciler (old): Recursive, cannot be interrupted
function stackReconcile(element, container) {
// Recursive call — cannot pause once started
const dom = createDOM(element);
element.children.forEach(child => {
stackReconcile(child, dom); // Deep recursion
});
container.appendChild(dom);
// If this takes 200ms, the main thread is blocked for 200ms
}
// Fiber reconciler (new): Iterative, can be interrupted
function fiberReconcile(rootFiber) {
let nextUnitOfWork = rootFiber;
function workLoop(deadline) {
// Process fibers until time runs out
while (nextUnitOfWork && deadline.timeRemaining() > 1) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
if (nextUnitOfWork) {
// More work remaining, request next frame
requestIdleCallback(workLoop);
} else {
// All work done, commit
commitRoot();
}
}
// Start work loop with idle callback
requestIdleCallback(workLoop);
}
Work Prioritization with Lanes
Fiber uses lanes to prioritize updates. Higher priority updates interrupt lower priority work.
// Lanes represent priority levels
const Lanes = {
NoLanes: 0b0000000000000000000000000000000,
SyncLane: 0b0000000000000000000000000000001, // Highest priority
InputContinuousLane: 0b0000000000000000000000000000010, // Input events
DefaultLane: 0b0000000000000000000000000000100, // Normal updates
TransitionLane: 0b0000000000000000000000000001000, // Transitions
IdleLane: 0b0000000000000000000000010000000, // Low priority
OffscreenLane: 0b0000000000000000000010000000 // Hidden content
};
// Priority-based scheduling
function scheduleUpdate(fiber, lane) {
// Mark fiber with its lane priority
fiber.lanes = mergeLanes(fiber.lanes, lane);
// Bubble priority up to root
let node = fiber;
while (node.return) {
node.return.childLanes = mergeLanes(node.return.childLanes, lane);
node = node.return;
}
// Schedule render with appropriate priority
if (lane === SyncLane) {
// Synchronous: process immediately
performSyncWork();
} else {
// Deferred: schedule with requestIdleCallback
scheduleCallback(lane, performConcurrentWork);
}
}
// If a Sync update comes in while processing a Default update:
// 1. Current work is paused
// 2. Sync work is processed
// 3. Sync work is committed (DOM updated)
// 4. Default work resumes from where it paused
The Work Loop in Detail
The work loop processes fibers in two phases: render and commit.
// Render phase (can be interrupted)
function performUnitOfWork(fiber) {
// 1. Begin work on this fiber
beginWork(fiber);
// 2. If fiber has a child, process child next (depth-first)
if (fiber.child) {
return fiber.child;
}
// 3. No child: complete this fiber and move to sibling
let current = fiber;
while (current) {
completeUnitOfWork(current);
if (current.sibling) {
return current.sibling; // Process sibling next
}
// No sibling: go back to parent
current = current.return;
}
// Reached the root: all work is done
return null;
}
function beginWork(fiber) {
// Determine if this fiber needs work
if (fiber.lanes === NoLanes) {
// No pending work, bail out
cloneChildFibers(fiber);
return;
}
// Process based on fiber tag
switch (fiber.tag) {
case FunctionComponent:
// Call the function component
const children = fiber.type(fiber.pendingProps);
reconcileChildren(fiber, children);
break;
case HostComponent:
// Create or update DOM element
reconcileChildren(fiber, fiber.pendingProps.children);
break;
case ClassComponent:
// Call render method
const rendered = fiber.stateNode.render();
reconcileChildren(fiber, rendered);
break;
}
}
// Commit phase (synchronous, cannot be interrupted)
function commitRoot(rootFiber) {
// Walk the effect list and apply DOM mutations
let effect = rootFiber.firstEffect;
while (effect) {
switch (effect.effectTag) {
case 'PLACEMENT':
// Insert new DOM node
break;
case 'UPDATE':
// Update existing DOM node
break;
case 'DELETION':
// Remove DOM node
break;
}
effect = effect.nextEffect;
}
}
How Fiber Enables Concurrent Rendering
Fiber's ability to pause and resume work enables React's concurrent features.
// Concurrent rendering: lower priority work yields to higher priority
// This is how useTransition works:
import { useTransition, useState } from 'react';
function SearchPage() {
const [query, setQuery] = useState('');
const [isPending, startTransition] = useTransition();
function handleChange(e) {
// High priority: update the input immediately
setQuery(e.target.value);
// Low priority: filter results (can be interrupted)
startTransition(() => {
setFilteredResults(filterData(e.target.value));
});
}
// While the transition is pending, isPending is true
// The input stays responsive because filtering yields
return (
<div>
<input value={query} onChange={handleChange} />
{isPending && <span>Updating...</span>}
<ResultsList data={filteredResults} />
</div>
);
}
Common Mistakes
- Assuming Fiber makes all updates asynchronous (sync updates like useEffect are still synchronous).
- Thinking Fiber eliminates all re-render costs (it only distributes work over time).
- Using useTransition for every update (only use it for expensive, non-urgent updates).
- Expecting concurrent features to work without React 18+ and the new root API.
- Misunderstanding that Fiber is React-specific (other frameworks use different approaches).
Practice Questions
- What problem does Fiber solve? The stack reconciler blocked the main thread during rendering. Fiber enables incremental, interruptible rendering.
- How does Fiber achieve interruptibility? By using a linked list fiber tree instead of recursive calls, which can be paused and resumed.
- What are lanes in Fiber? Priority levels that determine which updates are processed first.
- What are the two phases of Fiber reconciliation? Render phase (interruptible) and commit phase (synchronous).
Challenge
Build a simplified Fiber-like reconciler that processes a component tree using a work loop with requestIdleCallback. Implement priority levels where sync updates interrupt lower priority work. Demonstrate by rendering a large list with a concurrent search filter.
FAQ
Mini Project
Build a simple Fiber-inspired renderer. Implement a work loop that processes virtual nodes one at a time using requestIdleCallback. Add priority lanes for urgent (input) vs non-urgent (list filtering) updates. Show a visual indicator when the renderer yields to the browser.
What's Next
Lesson 8: Diffing Strategies
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro