跪拜 Guibai
← All articles
Frontend · React.js · React Native

React Fiber's 20 Fields Are the Entire Runtime

By 老王以为 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Understanding the Fiber data structure turns opaque React behavior—bail-outs, priority inversions, memory leaks from orphaned subtrees—into legible field-level mechanics. When a production app leaks FiberNodes, the developer who knows that `return`, `child`, and `alternate` form a reference graph can trace the root cause instead of guessing at the garbage collector.

Summary

A memory-leak investigation into a long-running React app traced thousands of unreclaimed FiberNodes back to a third-party router that forgot to sever a root reference. The fix was three lines, but the real payoff was a line-by-line reading of the `FiberNode` constructor in `ReactFiber.js`. Each of its twenty-some fields maps to a runtime capability: `tag` routes the reconciler to the correct `beginWork` branch, the `child`/`sibling`/`return` pointers turn a recursive tree into an interruptible linked list, `lanes` and `childLanes` propagate scheduling priority upward so the work loop can skip entire subtrees, and `flags`/`subtreeFlags` collect side effects as bitmasks so the commit phase knows exactly what DOM work is needed.

The double-buffering bridge `alternate` lets React compare old and new state without keeping two full copies of global bookkeeping—that job belongs to the separate `FiberRootNode`, which holds `pendingLanes`, the scheduler callback, and error handlers outside the Fiber tree itself. The design separates four identities (component description, tree structure, work state, side-effect tracking) into distinct field groups, which means the component model, scheduler, renderer, and DevTools teams can all work against the same data structure without stepping on each other.

Takeaways
Every Fiber node is a unit of work, not just a UI descriptor; it carries its own component type, tree pointers, pending state, priority lanes, and side-effect flags.
The `child`/`sibling`/`return` pointers flatten a component tree into a singly linked list that can be traversed with a `while` loop, making interruption and resumption possible without relying on the call stack.
`lanes` marks a node's own pending work; `childLanes` aggregates subtree work upward so the work loop can skip entire branches whose `childLanes` is zero.
`flags` and `subtreeFlags` use bitmasks to record side effects (Placement, Update, Deletion, Passive, Ref, etc.) on individual nodes and roll them up to the root, so the commit phase reads one integer to decide what DOM work to perform.
Deleted children are stored in the parent's `deletions` array rather than flagged on the child itself, because the deleted node won't be visited again during traversal.
`alternate` links the current and work-in-progress trees bidirectionally, enabling state comparison, node reuse, and an atomic pointer swap at commit time.
React's root is a two-layer structure: `FiberRootNode` holds global scheduling and error state that never participates in double-buffering, while `RootFiber` (tag `HostRoot`) is the actual tree entry point.
The `tag` field is a 32-value enum that acts as the reconciler's routing table; `beginWork` switches on it to decide how to process each node type.
`elementType` and `type` usually match but diverge for `ForwardRef` and `Lazy` wrappers, where the outer shell differs from the resolved inner component.
Conclusions

Fiber's design is a case study in how a single flat data structure, with no inheritance and no hidden state, can replace a whole family of specialized objects—the simplicity is what makes cloning, discarding, and reusing nodes cheap.

The four-identity split (component, tree, work, side effects) isn't just documentation; it's an organizational boundary that lets separate React teams evolve the scheduler, renderer, and component model against the same contract.

Bitmask-based lanes and flags are an underappreciated performance choice: they turn what would be array traversals and object lookups into single-cycle bitwise operations, and they compose cleanly with the upward-propagation pattern used by `childLanes` and `subtreeFlags`.

Calling the parent pointer `return` instead of `parent` is a deliberate semantic choice that reflects the traversal algorithm—it's a reminder that the Fiber tree is a work-list, not a static hierarchy.

The `deletions` array pattern (storing doomed children on the parent) is a generalizable trick for any tree transform where removed nodes won't be visited again but still need post-order cleanup.

Concepts & terms
Fiber Node
The core data structure of React's reconciler. A plain JavaScript object whose fields encode component identity, tree position (child/sibling/return pointers), pending work (props, state, update queue), scheduling priority (lanes), and side-effect flags. Each Fiber node is a unit of work that can be processed independently, enabling interruptible rendering.
Lanes
A 31-bit integer bitmask representing update priorities in React's concurrent scheduler. Individual bits correspond to priority levels; a node's `lanes` field records its own pending work, while `childLanes` aggregates subtree work upward so the work loop can quickly decide whether to descend into a branch.
Side-effect Flags (flags / subtreeFlags)
Bitmask fields on a Fiber node that record what DOM or lifecycle work is needed. `flags` marks the node itself (Placement, Update, Deletion, Passive for useEffect, Ref, etc.); `subtreeFlags` is the bitwise OR of all flags in the subtree, rolled up during the completeWork phase so the commit phase can read a single integer from the root.
Double Buffering (alternate)
React maintains two Fiber trees—current (what's on screen) and work-in-progress (the next version being built). Each node's `alternate` field points to its counterpart in the other tree, enabling state comparison, node reuse, and an atomic root-pointer swap at commit time.
FiberRootNode vs. RootFiber
React's root is a two-layer structure. FiberRootNode is a non-Fiber object that holds global state (pendingLanes, scheduler callback, error handlers) and never participates in tree traversal or double-buffering. RootFiber is a Fiber node with tag HostRoot that serves as the tree's entry point; its stateNode points back to the FiberRootNode.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗