What is Fiber in React? Understanding stateNode and the Virtual DOM Blueprint
The Confusion
I kept hearing about “Fiber” in React. Blog posts mentioned it. Conference talks praised it. Documentation referenced it. But what actually IS it?
Is it a new rendering engine? A virtual DOM replacement? Some magical optimization layer?
Every explanation I found used terms like “reconciliation algorithm,” “work scheduling,” and “incremental rendering.” Technical, sure, but not helpful for building intuition.
Then I dug into React’s source code and found something surprising: Fiber is just a JavaScript object. A plain, boring object with properties like child, sibling, return, and stateNode.
The Simple Truth
Fiber = In-memory JavaScript object blueprint of your JSX
stateNode = Reference to the actual DOM node or component instance
That’s it. No magic. No mysterious black box. Just structured data that describes what your UI should look like and how it connects to the real browser DOM.
What is a Fiber Node?
When you write JSX like this:
function App() { return ( <div id="container"> <h1>Hello</h1> <p>World</p> </div> );}React transforms each element into a Fiber node. A simplified Fiber structure looks like this:
{ // Identity tag: WorkTag, // Type: function component, class component, DOM element, etc. key: null | string, // React key for reconciliation type: any, // 'div', 'span', or component function/class
// Instance connection stateNode: any, // <-- THE KEY PROPERTY: actual DOM node or instance
// Tree structure (linked list) return: Fiber | null, // Parent fiber child: Fiber | null, // First child fiber sibling: Fiber | null, // Next sibling fiber
// State & Props pendingProps: mixed, // New props from render memoizedProps: mixed, // Props from previous render memoizedState: mixed, // State from previous render flags: Flags, // Side effects (update, delete, etc.)}Each Fiber represents one unit of work. The child, sibling, and return properties form a linked-list tree structure that React can traverse efficiently.
The Fiber Tree Visualized
Here’s how your JSX transforms into a Fiber tree:
JSX: Fiber Tree:------------------------------ ---------------------------------<App> AppFiber (FunctionComponent) <div id="container"> | <h1>Hello</h1> v <p>World</p> divFiber (HostComponent) </div> |</App> v h1Fiber ----> pFiber | | v v "Hello" "World"The return property points back to the parent (I drew arrows going down, but return goes back up).
What is stateNode?
The stateNode property is the critical bridge between React’s virtual world and the real browser DOM:
Component Type stateNode Value----------------- ----------------<div>, <span>, etc. Actual DOM element (document.createElement result)Class Component Class instance (this inside the component)Function Component null (no instance exists)For host components (DOM elements), stateNode holds the actual DOM node:
const divFiber = { tag: HostComponent, // 5 in React source type: 'div', stateNode: document.createElement('div'), // Real DOM node!};For class components, stateNode holds the class instance:
class Counter extends React.Component { state = { count: 0 }; render() { return <div>{this.state.count}</div>; }}
const classFiber = { tag: ClassComponent, // 1 in React source type: Counter, stateNode: new Counter(props), // The 'this' inside methods};For function components, stateNode is null because functions don’t have instances:
function Counter() { const [count, setCount] = useState(0); return <div>{count}</div>;}
const functionFiber = { tag: FunctionComponent, // 0 in React source type: Counter, stateNode: null, // No instance!};Why stateNode Matters
This is how React actually updates the real DOM. When the commit phase runs:
function commitUpdate(fiber) { const domNode = fiber.stateNode; // Get real DOM node const newProps = fiber.memoizedProps;
// Direct DOM manipulation if (newProps.className !== fiber.pendingProps.className) { domNode.className = newProps.className; }
if (newProps.style) { Object.assign(domNode.style, newProps.style); }
// ... handle other props}React doesn’t magically update the DOM. It uses stateNode to find and modify actual DOM elements.
Fiber Tree vs Virtual DOM
Here’s what confused me initially: they’re the same thing.
Concept Name Implementation Name----------------- -------------------Virtual DOM = Fiber Tree (React 16+)Virtual DOM Node = Fiber NodeReconciliation = Fiber ReconcilerBefore React 16, React used a “stack reconciler” that recursively processed updates. This was blocking - once rendering started, it couldn’t stop until finished.
React 16 introduced the “Fiber reconciler” with interruptible rendering:
Stack Reconciler (pre-React 16): render() ----[blocking]----> commit() (jank, frozen UI during render)
Fiber Reconciler (React 16+): render() --[chunk]--[chunk]--[chunk]--> commit() (browser can handle user input between chunks)This enables React 18’s concurrent features: transitions, suspense, and priority-based updates.
memoizedState vs stateNode
Another source of confusion: these two properties store different things.
Property What it stores-------------- ----------------stateNode DOM node OR class instancememoizedState Hook state for function components OR component state for class componentsFor function components with hooks, memoizedState stores a linked list of hook states:
function Counter() { const [count, setCount] = useState(0); // Hook 1 const [name, setName] = useState(''); // Hook 2
// fiber.memoizedState structure: // { memoizedState: 0, next: { memoizedState: '', next: null } }}This is why hooks must be called in the same order - React relies on the linked list structure to find each hook’s state.
Tracing a Real Component
Let me trace how a simple component becomes Fiber nodes:
function SimpleComponent() { const [value, setValue] = useState('hello'); return ( <div className="container"> <span>{value}</span> </div> );}This creates the following Fiber tree:
// Function component fiberconst simpleFiber = { tag: FunctionComponent, type: SimpleComponent, stateNode: null, memoizedState: { memoizedState: 'hello', next: null }, // useState hook child: divFiber,};
// Div fiberconst divFiber = { tag: HostComponent, type: 'div', stateNode: document.createElement('div'), // Real DOM node pendingProps: { className: 'container' }, child: spanFiber, return: simpleFiber,};
// Span fiberconst spanFiber = { tag: HostComponent, type: 'span', stateNode: document.createElement('span'), child: textFiber, return: divFiber,};
// Text fiberconst textFiber = { tag: HostText, stateNode: { nodeValue: 'hello' }, // Text content return: spanFiber,};How React Traverses the Fiber Tree
React uses a depth-first traversal pattern:
function traverseFiber(fiber) { let node = fiber;
while (node) { // 1. Process current node processFiber(node);
// 2. Go to child first (depth-first) if (node.child) { node = node.child; } // 3. No child? Try sibling else if (node.sibling) { node = node.sibling; } // 4. No child or sibling? Go back up to parent's sibling else { while (node && !node.sibling) { node = node.return; // Go back up } if (node) { node = node.sibling; } } }}This traversal happens during both the render phase (building the new tree) and commit phase (applying changes to DOM).
Key Takeaways
-
Fiber is just a data structure - A JavaScript object with tree links (
child,sibling,return) and state references (memoizedState,stateNode) -
stateNode is the DOM bridge - For host components, it’s the real DOM element. For class components, it’s the instance. For function components, it’s null.
-
Virtual DOM = Fiber Tree - Different names for the same concept. “Virtual DOM” is the abstraction; “Fiber” is React’s implementation.
-
Understanding this helps debugging - When React DevTools shows you a component tree, you’re looking at Fiber nodes. When performance suffers, understanding the Fiber tree helps identify bottlenecks.
-
Hooks rely on memoizedState order - The linked list of hook states explains why you can’t call hooks conditionally.
When This Knowledge Helps
- Debugging React DevTools Fiber tree view
- Understanding why concurrent mode improves performance
- Optimizing re-renders by understanding memoization
- Building custom React renderers (React Native, React Three Fiber)
- Debugging hydration mismatches in SSR
The next time someone talks about “Fiber architecture” or asks about React internals, you can confidently say: “It’s just a tree of JavaScript objects that describe your UI, with stateNode pointing to the real DOM.”
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 React Fiber Architecture - GitHub
- 👨💻 React as a UI Runtime - Dan Abramov
- 👨💻 Inside Fiber: In-depth overview of the new reconciliation algorithm
- 👨💻 React Documentation - Reconciliation
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments