© Bohua Xu

React Fiber

Dec 17, 2022 · 7min

Deep Dive into React Fiber: Architecture and Source Code Analysis

Introduction

React Fiber is a complete reimplementation of React’s core algorithm introduced in React 16. It is the culmination of over two years of research by the React team. The primary goal of React Fiber is to enable incremental rendering: the ability to split rendering work into chunks and spread it out over multiple frames.

Why Fiber Was Needed

Before Fiber, React used a synchronous reconciliation algorithm often referred to as the "stack reconciler" because it relied on the call stack. Once it started processing updates, it couldn’t be interrupted until it completed traversing the entire component tree. This could cause performance issues, especially in UI animations and transitions, leading to dropped frames and jank.

Core Concepts of Fiber

Fiber introduces a new internal architecture that fundamentally changes how React works under the hood. It reimplements the reconciliation algorithm with the following key goals:

  1. Incremental rendering: Split rendering work into chunks that can be paused and resumed
  2. Priority management: Assign different priorities to different types of updates
  3. Pause, abort, or reuse work: The ability to pause work and come back to it later
  4. Concurrency: Prepare multiple versions of the UI at the same time

The Fiber Data Structure

At its core, a Fiber is a JavaScript object that represents a unit of work. It’s also a node in a tree—the Fiber tree, which is React’s internal representation of the component tree.

Here’s a simplified version of the Fiber structure from React’s source code:

function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // Instance
  this.tag = tag;
  this.key = key;
  this.elementType = null;
  this.type = null;
  this.stateNode = null;

  // Fiber
  this.return = null;
  this.child = null;
  this.sibling = null;
  this.index = 0;

  this.ref = null;

  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;
  this.dependencies = null;

  this.mode = mode;

  // Effects
  this.flags = NoFlags;
  this.subtreeFlags = NoFlags;
  this.deletions = null;

  this.lanes = NoLanes;
  this.childLanes = NoLanes;

  this.alternate = null;
}
function FiberNode(
  tag: WorkTag,
  pendingProps: mixed,
  key: null | string,
  mode: TypeOfMode,
) {
  // Instance
  this.tag = tag;
  this.key = key;
  this.elementType = null;
  this.type = null;
  this.stateNode = null;

  // Fiber
  this.return = null;
  this.child = null;
  this.sibling = null;
  this.index = 0;

  this.ref = null;

  this.pendingProps = pendingProps;
  this.memoizedProps = null;
  this.updateQueue = null;
  this.memoizedState = null;
  this.dependencies = null;

  this.mode = mode;

  // Effects
  this.flags = NoFlags;
  this.subtreeFlags = NoFlags;
  this.deletions = null;

  this.lanes = NoLanes;
  this.childLanes = NoLanes;

  this.alternate = null;
}

Each Fiber node contains:

  • Information about the component type (function, class, etc.)
  • References to its parent, child, and sibling nodes
  • Input props and output state
  • Pointers to other Fibers forming the linked list
  • Work-in-progress alternate

Phases of Fiber Reconciliation

React Fiber reconciliation works in two main phases:

  1. Render/Reconciliation Phase: This is where React determines what changes need to be made to the DOM. This phase can be interrupted and is not committed directly to the DOM.

  2. Commit Phase: This is where React applies the changes to the DOM. This phase is uninterruptible to avoid showing an inconsistent UI.

Work Loop and Priorities

One of the most important aspects of Fiber is its work loop mechanism:

function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }
  
  if (!nextUnitOfWork && workInProgressRoot) {
    // We've completed all the work, commit the changes
    commitRoot();
  }
  
  requestIdleCallback(workLoop);
}
function workLoop(deadline) {
  let shouldYield = false;
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
    shouldYield = deadline.timeRemaining() < 1;
  }
  
  if (!nextUnitOfWork && workInProgressRoot) {
    // We've completed all the work, commit the changes
    commitRoot();
  }
  
  requestIdleCallback(workLoop);
}

The requestIdleCallback API allows React to schedule work during browser idle periods. This is how React can pause and resume work as needed.

Fiber introduces different priority levels for updates:

  • Immediate: Must be completed immediately (synchronous)
  • User-blocking: User interactions like clicks, typing (high priority)
  • Normal: Data updates (medium priority)
  • Low: Work that can be delayed but should eventually happen
  • Idle: Work that can be dropped if needed

Effects in Fiber

Effects (like lifecycle methods or hooks) are represented in Fiber using a linked list called the "effect list." This list contains all Fibers that need some work done for the commit phase.

Double Buffering

Fiber implements a technique called "double buffering" through the alternate property. At any time, there are two versions of the Fiber tree:

  1. The current tree, representing what’s currently rendered
  2. The work-in-progress tree, representing the future state being constructed

Once the work-in-progress tree is complete, React "flips" the pointers so that the work-in-progress tree becomes the current tree.

Fiber Reconciler Algorithm

At a high level, the Fiber reconciler works like this:

  1. Begin render phase by creating a new work-in-progress tree
  2. For each Fiber node in the tree:
    • Process updates and perform reconciliation
    • Create/update child Fibers as needed
    • Schedule effects if necessary
    • Return the next unit of work
  3. Once all work is complete, prepare for commit
  4. Commit all changes to the DOM in a single, uninterruptible phase
  5. Swap the current and work-in-progress trees

Conclusion

React Fiber represents a significant architectural shift that enables React to better utilize the browser’s capabilities. Its ability to pause, abort, and prioritize work allows for smoother animations, more responsive user interfaces, and better performance overall. As React continues to evolve, the Fiber architecture provides a solid foundation for future improvements like Concurrent Mode and Suspense.

Understanding Fiber is crucial for advanced React developers who want to grasp how React works under the hood and optimize their applications accordingly.

CC BY-NC-SA 4.0 2021-PRESENT © Bohua Xu