- Published on
Understanding the Virtual DOM and Fiber Tree in React
Introduction
The Document Object Model (DOM) is a programming interface for HTML and XML documents, but direct manipulation of the DOM can be slow and inefficient. This is where the Virtual DOM comes into play.
- createElement( )
- React Element
- Virtual DOM
- Fiber Nodes Tree
- Depth-First Traversal
- Real-Life Analogy
- Conclusion
createElement( )
In React, the HTML-like syntax, known as JSX, is a syntactic sugar that gets transpiled into React.createElement()
or _jsx()
during the build process using tools like Babel. 1
Each React.createElement()
call returns a plain JavaScript object called a React element. These elements are immutable and form a tree structure, representing the UI components and their hierarchy.

React Element
A React component is essentially a function that returns React elements. For example:
function App() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
const reactElementApp= (
<div className="counter">
<h2>Count: {count}</h2>
<button onClick={handleClick}>Increment</button>
</div>
);
console.log(reactElementApp);
return reactElementApp ;
}

Virtual DOM
When React renders the UI, it first invokes the component functions and traverses the returned React elements. This process continues recursively until React reaches scalar values (which are rendered as text nodes) or encounters null or undefined values (which render nothing). This process transforms JSX code into a tree of React elements, traditionally known as the 'virtual DOM'.
However, React elements are just plain JavaScript objects (POJOs) and don't directly help render a web page. The term "virtual DOM" can be misleading and is no longer used in the React official documentation.
Starting with React 16, a new fiber reconciler was introduced, which creates a corresponding fiber node for each React element. This fiber node facilitates a more efficient reconciliation process. If we think of the Virtual DOM in this context, it should be understood as a tree of fiber nodes.
Operations on the Virtual DOM are faster and more efficient than operations on the real DOM. Multiple Virtual DOM updates are batched into a single DOM update to minimize the number of real DOM manipulations.
Fiber Nodes Tree
Each fiber node is connected to others using properties child
, sibling
, and return
. This linked list structure facilitates React's operations. Each first child has a link to its parent, and all other children link to their previous sibling, but also to the parent. Below is an illustration of how the fiber tree is structured:
export function App() {
const myApp = (
<>
<h2>My App</h2>
<Counter></Counter>
<div>My App Content</div>
<h2>My App footer</h2>
</>
);
return myApp;
}
export default function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count => count + 1);
};
return (
<>
<button onClick={handleClick}>Update Counter</button>
<span>The count {count}</span>
</>
);
}

Depth-First Traversal
The fiber tree uses this linked list structure for several reasons:
- Efficient depth-first traversal
The linked list pointers (child
,sibling
,return
) make it easy to navigate the tree.
Here's an example of how depth-first traversal can be achieved:
function performWork(fiber) {
while(fiber) {
// Process the current fiber node
console.log(fiber.element);
// Check if we need to pause
if(shouldPauseWork()) {
saveState(fiber);
return; // Exit the function to pause
}
// Traverse to the child first
if(fiber.child) {
fiber = fiber.child;
} else {
// If no child, move to sibling
while(!fiber.sibling && fiber.return) {
fiber = fiber.return; // Move up the tree
}
fiber = fiber.sibling; // Move to the next sibling
}
}
}
Asynchronous rendering
The linked list structure enables React to support pausing and resuming rendering, allowing it to handle higher-priority updates first. React breaks down the work into small chunks, or time slices (5 milliseconds), so they can be completed within a single frame, which is approximately 8ms on a 120Hz monitor. During traversal, if React decides to pause the work, it saves the state of the traversal (current node, remaining work) to resume from the same point later.
The definition of time slices can be found in the following source code:
https://github.com/facebook/react/blob/v18.3.1/packages/scheduler/src/SchedulerFeatureFlags.js#L13Efficiently update fiber nodes
o Adding a new child using thechild
pointer.
o Re-order or adding new sibling at the same level using thesibling
pointer.
o Move back up to the parent using thereturn
pointer.
Real-Life Analogy
A useful analogy for the Virtual DOM is the blueprint of a house. Imagine you want to renovate a room in your house. The physical arrangement of the room—its furniture and decor—represents the real DOM. The Virtual DOM acts like the blueprint of the entire house. To renovate, you first create a revised (work-in-progress) blueprint that marks changes, such as adding a window or rearranging walls. You then compare this revised blueprint with the original to identify the necessary updates, and finally, apply all modifications to the room in one go.
The advantage of this approach is that it allows you to prioritize, pause, and batch updates, handle errors without affecting the actual room, and ensure all changes are applied correctly. Similarly, React uses the Virtual DOM to efficiently manage and update the real DOM, ensuring that all modifications are made in an optimized and controlled manner.
Conclusion
The Virtual DOM is not just a technical innovation; it's a paradigm shift in how we think about rendering web pages. By allowing developers to work with a virtual representation of the real UI, React provides a powerful tool for building dynamic and responsive applications efficiently.
Footnotes
Before React 17, JSX elements were converted into
React.createElement()
during the build process. Starting with React 17, they utilize_jsx()
and_jsxs()
. Because JSX was compiled into React.createElement, React needed to be in scope when using JSX._jsx()
is a new entry point to the React package, allowing React to be excluded from the scope, leading to performance improvements and simplifications._jsxs()
is used for fragments (multiple adjacent elements). ↩