How React Virtual DOM Works

Introduction
Modern web applications update their user interfaces constantly. Buttons change state, notifications appear, lists update, and forms respond to user input in real time.
If every change directly manipulated the browser's DOM (Document Object Model), applications could become slow and inefficient. This is the problem React's Virtual DOM was designed to solve.
In this article, we'll explore how the Virtual DOM works, why React uses it, and how React efficiently updates only the parts of the UI that actually change.
The Problem: Direct DOM Manipulation is Expensive
The browser uses the Real DOM to represent everything displayed on a webpage.
For example:
<h1>Hello World</h1>
<button>Click Me</button>
These elements become nodes inside the browser's DOM tree.
When JavaScript changes the DOM:
document.getElementById("title").innerText = "Updated";
the browser may need to:
Recalculate layouts
Repaint elements
Recompute styles
Update the screen
For small applications this is manageable.
However, in large applications with hundreds or thousands of elements, frequent DOM updates become expensive.
This is where React introduces the Virtual DOM.
What is the Virtual DOM?
The Virtual DOM is a lightweight JavaScript representation of the Real DOM.
Instead of immediately changing the browser's DOM, React first updates this virtual representation.
Example:
Virtual DOM
App
├── Header
├── Button
└── Footer
Think of the Virtual DOM as a blueprint or copy of the UI stored in memory.
React can compare different versions of this blueprint much faster than updating the browser's actual DOM repeatedly.
Real DOM vs Virtual DOM
| Real DOM | Virtual DOM |
|---|---|
| Actual browser structure | JavaScript representation |
| Updates are expensive | Updates are fast |
| Direct manipulation affects performance | Comparison happens in memory |
| Browser must repaint frequently | Minimal browser updates |
| Slower for large UI changes | Optimized for frequent updates |
The Virtual DOM does not replace the Real DOM.
Instead, it acts as an intelligent layer between React and the browser.
Initial Render Process in React
When a React application loads, the following process occurs:
Step 1: Component Creation
React components return JSX.
Example:
function App() {
return <h1>Hello React</h1>;
}
Step 2: Virtual DOM Creation
React converts JSX into a Virtual DOM tree.
App
│
▼
h1
│
▼
Hello React
Step 3: Real DOM Creation
React creates the corresponding browser DOM elements.
Component
│
▼
Virtual DOM
│
▼
Real DOM
This completes the first render.
What Happens When State or Props Change?
React applications are dynamic.
Example:
const [count, setCount] = useState(0);
When:
setCount(count + 1);
is executed:
State changes
Component re-renders
New Virtual DOM is generated
Importantly:
React does not immediately rebuild the entire browser DOM.
Instead, it creates a new Virtual DOM tree and compares it with the previous one.
Creation of a New Virtual DOM Tree
Suppose the UI initially displays:
Count: 0
Virtual DOM Tree:
App
│
▼
Count: 0
After clicking a button:
Count: 1
React creates a new Virtual DOM tree:
App
│
▼
Count: 1
Now React has:
Old Virtual DOM
New Virtual DOM
The next step is comparison.
What is Diffing (Reconciliation)?
Diffing, also known as reconciliation, is the process of comparing:
Old Virtual DOM
with
New Virtual DOM
React analyzes both trees and determines what actually changed.
Example:
Old Tree
App
└── Count: 0
New Tree
App
└── Count: 1
React detects that only the text content changed.
Everything else remains the same.
This comparison process is called reconciliation.
How React Finds Minimal Required Changes
Instead of rebuilding everything, React identifies only the differences.
Example:
Before
<h1>Count: 0</h1>
After
<h1>Count: 1</h1>
React recognizes:
✅ Same element type (h1)
❌ Different text content
Therefore:
Only the text node needs updating.
This dramatically reduces the amount of work required.
Updating Only Changed Nodes in the Real DOM
After diffing is complete, React applies only the necessary changes.
Example:
Old UI
Header
Count: 0
Footer
Updated UI:
Header
Count: 1
Footer
React updates:
Count: 0
to
Count: 1
while leaving:
Header
Footer
untouched.
This process is known as a minimal update patch.
Why This Approach Improves Performance
Without the Virtual DOM:
State Change
│
▼
Direct Real DOM Update
│
▼
Layout + Paint + Reflow
With the Virtual DOM:
State Change
│
▼
New Virtual DOM
│
▼
Diffing
│
▼
Minimal Changes
│
▼
Real DOM Update
Benefits:
Faster rendering
Fewer DOM operations
Better user experience
Improved scalability
Smoother UI updates
Because browser DOM operations are expensive, reducing them improves performance significantly.
React Render → Diff → Commit Flow
React's update lifecycle can be simplified into three phases.
1. Render Phase
React creates a new Virtual DOM tree.
State Change
│
▼
Render
│
▼
New Virtual DOM
2. Diff Phase
React compares old and new Virtual DOM trees.
Old Tree
│
▼
Compare
▲
│
New Tree
Differences are identified.│
3. Commit Phase
React updates the Real DOM.
Changes Found
│
▼
Commit
│
▼
Real DOM Updated
Users now see the updated interface.
Complete React Update Lifecycle
User Action
│
▼
State / Props Change
│
▼
Render Phase
│
▼
Create New Virtual DOM
│
▼
Diffing (Reconciliation)
│
▼
Find Minimal Changes
│
▼
Commit Phase
│
▼
Update Real DOM
│
▼
Updated UI
Architecture Diagrams
Initial Render Flow
React Component
│
▼
Virtual DOM
│
▼
Real DOM
│
▼
Browser Screen
State Update Flow
State Change
│
▼
New Virtual DOM Tree
│
▼
Diffing
│
▼
Minimal Updates
│
▼
Real DOM
Old Tree vs New Tree
Old Tree
App
└── Count: 0
│
▼
New Tree
App
└── Count: 1
Minimal Patch Application
Before
Header
Count: 0
Footer
│
▼
Patch
Count: 1
│
▼
After
Header
Count: 1
Footer
Conclusion
React's Virtual DOM provides an efficient way to update user interfaces without constantly manipulating the browser's Real DOM. Whenever state or props change, React creates a new Virtual DOM tree, compares it with the previous version through a process called reconciliation, identifies the minimal required changes, and updates only the affected nodes in the Real DOM.
This render → diff → commit approach allows React applications to remain fast, responsive, and scalable even as user interfaces become more complex. By understanding this mental model, developers can better appreciate how React optimizes performance while keeping UI development simple and predictable.
