Prior to React 16, updates were processed synchronously using a recursive traversal algorithm (the Stack Reconciler). Once an update began, React could not yield control to the browser. This could block the main thread for several frames, leading to stuttering animations and input lag.
To resolve this, the React core team developed React Fiber, a complete rewrite of the reconciliation algorithm designed to enable concurrent rendering.
1. What is a Fiber?
At its core, a Fiber is a plain JavaScript object representing a unit of work. It maps directly to a component instance and keeps track of hook queues, updates, and child references:
interface Fiber {
tag: WorkTag; // Identifies component type (Function, Class, Host)
key: null | string; // React key identifier
type: any; // Component or HTML element type
stateNode: any; // Reference to DOM node or instance
child: Fiber | null; // First child pointer
sibling: Fiber | null; // Sibling component pointer
return: Fiber | null; // Parent component pointer
memoizedState: any; // Hooks state queue list
alternate: Fiber | null; // Reference to alternate buffer node
}
Fiber nodes act as a virtual call stack. This allows React to pause, resume, prioritize, or discard rendering tasks dynamically.
2. The Dual-Buffering Strategy
React Fiber manages updates using a dual-buffering technique to prevent partial renders:
- Current Tree: Represents the state currently visible to the user in the DOM.
- Work-in-Progress (WIP) Tree: Built in the background when updates are triggered. React traverses the active fibers, evaluates update queues, and constructs the WIP tree incrementally.
Once the WIP tree is fully constructed and prepared, React swaps the root pointer, committing the updates in a single frame to prevent visual layout shifts.
3. The Reconciler Phase Split
To coordinate concurrent updates, React splits reconciliation into two distinct phases:
Phase 1: Render / Reconciliation (Interruptible)
- Action: React builds the work-in-progress tree, comparing fiber nodes and collecting side effects.
- Threading: This phase runs asynchronously. If the browser needs to process a high-priority user interaction (like a keypress), React yields control of the main thread and resumes rendering after the interaction is complete.
Phase 2: Commit (Uninterruptible)
- Action: React applies the calculated updates directly to the DOM and runs lifecycle hooks (
useEffect,useLayoutEffect). - Threading: This phase runs synchronously in a single transaction to prevent layout flickering.
Using concurrent features like useTransition allows you to manage heavy rendering tasks smoothly without blocking user interactions.