Table of Contents
- What is React Fiber?
- The Need for a New Reconciliation Engine
- Key Goals of React Fiber
- Core Concepts of Fiber Architecture
- How Fiber Works: A Step-by-Step Walkthrough
- Advanced Features Enabled by Fiber
- Performance Benefits of Fiber
- Challenges and Considerations
- Conclusion
- References
What is React Fiber?
At its core, React Fiber is a reimplementation of React’s reconciliation algorithm—the process that determines how to update the DOM when component state or props change. The term “Fiber” refers to the new unit of work in React, replacing the traditional call stack-based approach with a more flexible, tree-based structure.
Unlike the stack reconciler, which processed updates synchronously in a single pass (often blocking the main thread for long periods), Fiber allows React to:
- Break rendering work into smaller, interruptible chunks.
- Prioritize tasks based on their urgency (e.g., user input vs. background data loading).
- Pause, resume, or abort work as needed.
- Reuse previously completed work.
In short, Fiber transforms React from a synchronous renderer into an asynchronous, prioritizing scheduler, laying the groundwork for modern features like Concurrent Mode and Suspense.
The Need for a New Reconciliation Engine
Before Fiber, React used a stack reconciler that relied on recursion to traverse the component tree. Here’s why this became problematic:
Limitations of the Stack Reconciler:
- Synchronous Execution: The stack reconciler processed the entire component tree in one go. For large apps with complex component hierarchies, this could block the main thread for 100ms or more—far longer than the 16ms threshold required for smooth 60fps animations.
- No Prioritization: All updates (e.g., a button click vs. a background data refresh) were treated equally. Critical user interactions (like typing) would get delayed by less urgent work, leading to unresponsive UIs.
- No Asynchronous Support: The stack reconciler couldn’t pause to wait for asynchronous operations (e.g., fetching data), forcing developers to use workarounds like
setStatecallbacks orcomponentDidMount.
These issues became increasingly apparent as React apps scaled, prompting the React team to rebuild the reconciliation engine from the ground up.
Key Goals of React Fiber
Fiber was designed with specific objectives to address the stack reconciler’s flaws:
- Incremental Rendering: Break the rendering process into small chunks and spread them across multiple frames.
- Prioritization: Assign priority levels to different tasks (e.g., user input > animations > data fetching).
- Suspension: Pause rendering to wait for asynchronous operations (e.g., loading data or code) and resume when ready.
- Reusability of Work: Reuse previously computed work if it’s still valid.
- Abortable Work: Discard work that’s no longer needed (e.g., if a component unmounts mid-render).
Core Concepts of Fiber Architecture
To understand Fiber, let’s unpack its foundational concepts:
Fiber Nodes: The Unit of Work
A Fiber node is the building block of the Fiber architecture. It represents a unit of work and replaces the call stack frame used in the stack reconciler. Each component (class or function) has a corresponding Fiber node, which stores:
- Component Type: The type of component (e.g.,
div,MyComponent). - Props: The props passed to the component.
- State: The component’s current state.
- DOM Node: A reference to the associated DOM element (for host components like
div). - Child/Return/Sibling Pointers: References to child, parent (return), and sibling Fiber nodes (to traverse the tree).
- Effect Tag: A flag indicating what kind of change needs to be applied (e.g.,
Update,Placement,Deletion). - Priority: The priority level of the work for this node.
Example Fiber node structure (simplified):
{
type: 'div', // Component type
props: { className: 'container' }, // Props
stateNode: document.createElement('div'), // DOM node
child: fiberNodeForChildComponent, // Child Fiber
sibling: nextFiberNodeInSameLevel, // Sibling Fiber
return: parentFiberNode, // Parent Fiber
effectTag: 'Update', // Pending change
priority: 'UserBlocking', // Task priority
}
Fiber Tree Structure
React maintains two Fiber trees at all times:
- Current Tree: Represents the current state of the DOM (i.e., what’s rendered on the screen).
- Work-in-Progress (WIP) Tree: A copy of the current tree where React performs all updates. This allows React to work on changes without mutating the current tree until ready.
When updates are committed, the WIP tree becomes the new current tree (via a pointer swap), a process called double buffering. This minimizes DOM mutations and ensures consistency.
Reconciliation vs. Commit Phases
Fiber splits rendering into two distinct phases:
1. Reconciliation Phase (aka “Render Phase”)
- Purpose: Calculate the changes needed to update the UI (diffing the current and WIP trees).
- Behavior: Can be interrupted, paused, or resumed to prioritize higher-urgency tasks.
- Output: A list of “effects” (changes to apply, e.g., adding/removing nodes, updating attributes).
2. Commit Phase
- Purpose: Apply the changes calculated in the reconciliation phase to the DOM.
- Behavior: Synchronous and uninterruptible (to avoid inconsistent UI states).
- Actions:
- Update the DOM.
- Call lifecycle methods (e.g.,
componentDidMount,useEffectcallbacks). - Update refs.
Work Scheduling and Prioritization
Fiber’s most powerful feature is its ability to schedule work based on priority. React’s scheduler (a separate package, scheduler) coordinates this by:
- Using
requestIdleCallback-like logic to utilize browser idle time (though React now uses a custom implementation for better control). - Assigning priority levels to tasks.
Priority Levels (from highest to lowest):
- Immediate: Must run synchronously (e.g.,
flushSync). - UserBlocking: High-priority user interactions (e.g., click, typing, drag; ~250ms timeout).
- Normal: Default priority for most updates (e.g.,
setState; ~5000ms timeout). - Low: Can be deferred (e.g., background data loading; ~10,000ms timeout).
- Idle: Lowest priority, can be dropped if no time remains (e.g., logging).
How Fiber Works: A Step-by-Step Walkthrough
Let’s break down the Fiber workflow when a component updates (e.g., via setState or useState):
Step 1: Trigger an Update
An update is triggered (e.g., user clicks a button, calling setState). React creates an update object with the new state and schedules work.
Step 2: Schedule Work
The scheduler assigns a priority to the update (e.g., UserBlocking for a button click). It then queues the work to run when the browser is idle (via the scheduler’s scheduleCallback).
Step 3: Reconciliation Phase (Work Loop)
React enters the reconciliation phase, processing the Fiber tree in a work loop. The loop follows these steps for each Fiber node:
a. Perform Work on the Current Fiber
- Update the component’s props/state.
- Call lifecycle methods (e.g.,
getDerivedStateFromProps) or hooks (e.g.,useMemo). - Reconcile children: Compare the current children with the new children (returned by
render), creating/updating/deleting Fiber nodes as needed.
b. Yield to Higher-Priority Work
After processing a Fiber node, React checks if there’s remaining time in the current frame or if a higher-priority task has arrived. If so, it pauses work, saves the current progress (via the WIP tree), and yields to the main thread.
c. Resume Work Later
When the browser is idle again, the scheduler resumes the work loop from where it left off, continuing to process the next Fiber node (child, sibling, or parent, via the child, sibling, and return pointers).
Step 4: Complete Reconciliation
Once all Fiber nodes are processed, the reconciliation phase generates a list of effects (e.g., “add this node”, “update that attribute”).
Step 5: Commit Phase
React enters the commit phase, applying the effects to the DOM:
- Before Mutations: Call
getSnapshotBeforeUpdate(if used). - Mutate DOM: Add/remove/update DOM nodes based on effect tags.
- After Mutations: Call lifecycle methods (
componentDidMount,componentDidUpdate) and hook effects (useEffectcallbacks).
Step 6: Update the Current Tree
The WIP tree (now containing all updates) becomes the new current tree, and the process resets for the next update.
Advanced Features Enabled by Fiber
Fiber’s architecture unlocked several game-changing React features:
Concurrent Mode
Concurrent Mode (now integrated into React 18 as “concurrent rendering”) allows React to interrupt, pause, or resume rendering. This ensures high-priority tasks (e.g., typing) aren’t blocked by low-priority work (e.g., rendering a large list).
Suspense for Data Fetching
Suspense lets components “suspend” rendering while waiting for asynchronous data (e.g., API calls). Fiber’s ability to pause and resume work makes this possible:
// Example: Suspense with data fetching
function Profile() {
const user = fetchUser(); // Suspends until data loads
return <h1>{user.name}</h1>;
}
function App() {
return (
<Suspense fallback={<Spinner />}>
<Profile />
</Suspense>
);
}
Transitions
startTransition marks updates as non-urgent, allowing React to prioritize user interactions over background work (e.g., filtering a list while the user types):
function Search() {
const [input, setInput] = useState("");
const [results, setResults] = useState([]);
function handleChange(e) {
setInput(e.target.value);
// Mark this update as a low-priority transition
startTransition(() => {
setResults(filterData(e.target.value));
});
}
return <input value={input} onChange={handleChange} />;
}
Performance Benefits of Fiber
Fiber delivers tangible improvements for React apps:
- Smoother User Interactions: By prioritizing user input, Fiber ensures clicks, typing, and drags feel responsive, even during heavy rendering.
- Reduced Jank: Breaking work into chunks prevents long main-thread blocks, maintaining 60fps animations.
- Better Asynchronous Handling: Suspense and transitions simplify async workflows, reducing boilerplate and improving perceived performance.
- Scalability: Fiber handles large component trees more efficiently, making React viable for complex UIs (e.g., dashboards, data grids).
Challenges and Considerations
While Fiber improves React’s performance, it introduces complexity:
- Debugging: Interrupted work can make it harder to trace state updates (React DevTools helps with this).
- Lifecycle Changes: Legacy lifecycles like
componentWillMountare unsafe in concurrent mode (React recommendsgetDerivedStateFromPropsor hooks instead). - Starvation Risk: Low-priority tasks (e.g., logging) might never run if high-priority tasks continuously interrupt them.
- Scheduler Overhead: The scheduler adds minor overhead, though this is negligible for most apps.
Conclusion
React Fiber is a foundational shift in how React renders UIs, transforming it from a synchronous library into an asynchronous, prioritizing engine. By breaking work into chunks, prioritizing tasks, and enabling features like Concurrent Mode and Suspense, Fiber has made React more performant and flexible than ever.
Whether you’re building a small app or a large enterprise solution, understanding Fiber helps you write more efficient React code and leverage modern features to create seamless user experiences. As React continues to evolve (e.g., with Server Components), Fiber will remain its core, powering the next generation of frontend applications.
References
- React Fiber Architecture (Andrew Clark, React Core Team)
- React Official Documentation: Concurrent Mode
- React Scheduler Package
- Dan Abramov’s “Fiber: Under the Hood” (React Conf 2017)
- React Working Group: Fiber Principles
- Suspense for Data Fetching (React Docs)