In React 15, we hit a wall: the "Stack" was too rigid. We realized we needed to decouple Diffing (calculating changes) from Patching (writing to the DOM). More importantly, we needed the ability to pause execution for high-priority tasks like user input.
React 16 introduced Fiber—a complete rewrite of the core reconciliation engine. Fiber allows React to pause, resume, and prioritize work, giving "wings" to the user experience.
1. The Foundation: What is a "Fiber"?
To understand Fiber, we must first distinguish between a React Element and a Fiber Node.
React Element
These are plain JavaScript objects returned from render(). They are immutable. Every time a component renders, React throws away the old elements and creates new ones.
Fiber Node
A Fiber Node is a mutable internal object that represents the "real" state of your application. It acts as the unit of work. While elements are recreated, Fiber nodes are reused and persistent. They represent the actual UI components on the screen.
If you looked inside a Fiber node, you would see these key technical fields:
stateNode: The actual DOM element or class instance.type: The function or class associated with the fiber.pendingPropsvsmemoizedProps: "New data" coming in vs "Current data" already rendered.updateQueue: A linked list of state changes waiting to be processed.effectTag: A bitmask (e.g., 0b001) that tracks what needs to be done (Placement, Update, etc.).
The Linked List Structure
Fiber replaced the old recursive tree with a Singly Linked List. Each Fiber node has three critical pointers that allow React to traverse the tree without using the JavaScript Call Stack:
- Child: Points to the first child.
- Sibling: Points to the next sibling.
- Return: Points back to the parent.
2. The Internal Engine: The Work Loop
The Work Loop is the heart of React 16. It manages how much time is spent on reconciliation using Cooperative Scheduling.
-
shouldYield(): The loop constantly asks the browser: "Do you have urgent work for me?" (viarequestIdleCallback). If the browser needs to paint a frame, React pauses. - Expiration Times: React 16 used Expiration Times to prioritize updates. A user typing gets an earlier expiration (High Priority) than a data fetch (Low Priority).
3. The Two-Phase Reconciliation Process
React 16 fundamentally splits rendering into two distinct phases. This is the "secret sauce" that allows for interruptible rendering.
Phase 1: The Render Phase (Interruptible)
This phase is asynchronous. React traverses the existing Fiber tree (the "Current" tree) and calculates exactly what needs to change. During this traversal, React is doing two massive things: Creating the WIP Tree and Building the Effect List.
1. The Trigger: State Update
When setState is called, React creates an Update Object, places it in the updateQueue of that Fiber, and signals the scheduler. React then starts at the HostRoot and begins creating a Work-In-Progress (WIP) Tree. This WIP tree is a "draft" version of the Fiber nodes that will eventually replace the Current tree.
2. The unit of work: beginWork()
React moves down the tree calling beginWork() for each fiber node.
Cloning: React clones the Fiber from the "Current" tree into the "WIP" tree.
Bailout: If
pendingPropsequalsmemoizedPropsand there's no update in the queue, React "bails out" and skips that subtree, simply reusing the old nodes.Diffing & Effect Tags: If changes are found, React calculates the difference and marks the WIP Fiber with an Effect Tag using a bitmask (e.g.,
Placement,Update).
3. Prioritization & Interruption
Because React is working on a WIP Tree in the background, it can afford to be interrupted. If a high-priority event (like a keystroke) arrives, React pauses the creation of the WIP tree.
If the high-priority work doesn't affect the data React was just calculating, it resumes the WIP tree.
If it does change the same data, React discards the half-finished WIP tree and starts fresh.
4. The Backtrack & The Effect List: completeWork()
Once React reaches a leaf node (no more children), it starts moving back up the tree via completeWork(). This is where the Effect List is born.
Physical Preparation: React prepares the DOM nodes for the WIP fiber (but does not touch the screen yet).
The "Christmas Lights" (Effect List): As React backtracks, it collects all the Fibers that have Effect Tags and links them together into a linear linked list.
The Benefit: By the time React reaches the Root, it has a separate, tiny list of "dirty" nodes. It doesn't need to look at the whole tree anymore; it just needs to follow this list.
Phase 2: The Commit Phase (Synchronous)
Now that the "Math" is done and the WIP Tree is ready, React enters the Commit Phase. This is synchronous and uninterruptible to prevent visual glitches.
5. DOM Updates & The Swap
- DOM Update: React follows the Effects List (the shortcut) to jump directly to nodes that need changing.
- Double Buffering (The Swap): React maintains two trees: Current (on screen) and WIP (the draft). Once the DOM is patched, React performs a "Pointer Swap":
FiberRoot.current = WorkInProgressTree
Instantly, the "Draft" becomes the new reality.
6. Post-Update Lifecycles
React runs side effects: componentDidMount, componentDidUpdate, and updates refs. The main thread is then released back to the browser.
Conclusion: From Blocking to Cooperative
React 16 didn't just add features; it gave React a brain. By moving from a rigid "Stack" to a flexible "Linked List" of Fibers, React stopped being a blocking force and became a cooperative citizen of the browser.
The secret was making the update process Asynchronous. Instead of finishing the whole UI in one go, React learned to:
Break work into tiny chunks (Fiber nodes).
Pause if the browser had something more important to do.
Draft the new UI in the background (WIP Tree) without touching the screen.
Commit everything in one lightning-fast, synchronous burst.
By understanding beginWork, completeWork, and effectTag bitmasks, you’ve mastered the mechanics of the Fiber engine. But while React 16 gave us the engine, it didn't yet have the smart "traffic control" system to handle multiple updates at once.
In the next part, we’ll see how React 18 took this Fiber engine and added "Lanes"—the traffic control system that finally unlocked the full power of Concurrent React.
📚 Deep Dive References
If you want to look at the original documents that inspired this architecture, I highly recommend these:
-
The Fiber Architecture (The Official Design Doc): Written by Andrew Clark, this is the original blueprint that explained why React needed a rewrite.
-
Lin Clark’s "A Cartoon Guide to Fiber": This is the most famous explanation of the Fiber algorithm ever created. It’s perfect for visual learners.
-
Inside Fiber: In-depth overview of the new reconciliation algorithm: A legendary technical blog by Max Koretskyi that dives into the source code of beginWork and completeWork.

Top comments (0)