Skip to main content

Command Palette

Search for a command to run...

How React Virtual DOM Works Under the Hood

Updated
•6 min read•View as Markdown
How React Virtual DOM Works Under the Hood

Modern web applications constantly update the user interface. A chat app receives new messages, a dashboard refreshes statistics, and an e-commerce site updates cart totals instantly. Directly manipulating the browser’s DOM for every small change becomes expensive as applications grow larger. React solves this problem using the Virtual DOM.

Understanding how the Virtual DOM works is important because it explains why React applications can remain fast and manageable even when the UI changes frequently.

The Problem the Virtual DOM Solves

The browser’s Real DOM is not designed for high-frequency updates. Every time JavaScript modifies the DOM, the browser may need to:

  • Recalculate styles

  • Recompute layout

  • Repaint elements

  • Re-render parts of the page

These operations are computationally expensive.

For example, imagine a list containing 1,000 items. If only one item changes but the application updates the entire DOM tree, performance suffers unnecessarily. Frequent direct DOM manipulations can make applications slow and difficult to optimize manually.

Before frameworks like React, developers often had to manually track:

  • Which element changed

  • Which DOM node should update

  • Which parts should remain untouched

This becomes error-prone in large applications. React introduced the Virtual DOM to automate this efficiently.

Real DOM vs Virtual DOM

Real DOM

The Real DOM is the actual browser structure rendered on the screen.

Example:

<div>
  <h1>Hello</h1>
</div>

This structure exists inside the browser memory and directly affects what users see.

Characteristics of the Real DOM:

  • Directly tied to rendering

  • Updates are expensive

  • Large changes can trigger layout recalculations

  • Manipulating many nodes frequently reduces performance

Virtual DOM

The Virtual DOM is a lightweight JavaScript representation of the Real DOM. Instead of changing the browser DOM immediately, React first creates and updates this virtual representation.

Example representation:

{
  type: "div",
  props: {
    children: [
      {
        type: "h1",
        props: {
          children: "Hello"
        }
      }
    ]
  }
}

Characteristics of the Virtual DOM:

  • Stored in JavaScript memory

  • Faster to create and compare

  • Does not directly affect rendering

  • Allows React to calculate minimal updates before touching the Real DOM

React minimizes expensive Real DOM operations by first working with cheap JavaScript objects.

Initial Render Process in React

When a React application starts, React performs an initial render.

Suppose we have:

function App() {
  return <h1>Hello React</h1>;
}

Step 1: JSX Conversion

React converts JSX into JavaScript objects.

React.createElement("h1", null, "Hello React");

Internally this becomes a Virtual DOM node.

Step 2: Build Virtual DOM Tree

React creates a complete Virtual DOM tree representing the UI structure.

Example:

App
 └── h1
      └── "Hello React"

Step 3: Create Real DOM Nodes

React converts this Virtual DOM structure into actual browser DOM nodes.

The browser finally renders:

<h1>Hello React</h1>

This is called the mounting phase.

How State or Props Changes Trigger Re-render

React components re-render whenever:

  • State changes

  • Props change

  • Parent components re-render

Example:

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}

When setCount() runs:

  1. React schedules an update

  2. The component function executes again

  3. A new Virtual DOM tree is created

  4. React compares old vs new trees

  5. Only required DOM updates are applied

React does not directly update the DOM immediately after state changes. It first computes what actually changed.

Creation of a New Virtual DOM Tree

Every render creates a new Virtual DOM representation.

Suppose the initial UI is:

<button>0</button>

After clicking:

<button>1</button>

React creates:

Old Virtual DOM

{
  type: "button",
  children: ["0"]
}

New Virtual DOM

{
  type: "button",
  children: ["1"]
}

Now React compares both trees. This comparison process is called reconciliation.

What Diffing (Reconciliation) Means

Diffing is the process where React compares:

  • Previous Virtual DOM tree

  • New Virtual DOM tree

The goal is to identify the smallest possible set of changes needed.

Instead of rebuilding the whole UI, React calculates:

  • Which nodes changed

  • Which nodes stayed identical

  • Which nodes were added or removed

This process is called the reconciliation algorithm.

How React Finds Minimal Required Changes

React uses several optimization assumptions to make diffing efficient.

1. Different Element Types Mean Full Replacement

If:

<div>Hello</div>

changes to:

<section>Hello</section>

React destroys the old subtree and creates a new one because the element types differ.

2. Same Element Types Reuse Existing Nodes

If:

<button className="red">Click</button>

changes to:

<button className="blue">Click</button>

React keeps the same <button> node and updates only the class.

3. Keys Help Track List Items

Example:

items.map(item => (
  <li key={item.id}>{item.name}</li>
))

Keys help React identify which list items changed, moved, or stayed the same. Without keys, React may unnecessarily re-render multiple elements.

Updating Only Changed Nodes in the Real DOM

After diffing finishes, React applies only the necessary changes to the Real DOM.

Example:

Initial UI:

<ul>
  <li>A</li>
  <li>B</li>
</ul>

Updated UI:

<ul>
  <li>A</li>
  <li>C</li>
</ul>

React updates only:

<li>B</li>

to:

<li>C</li>

The rest of the DOM remains untouched. This selective updating is the major performance advantage.

Why This Approach Improves Performance

The Virtual DOM improves performance mainly because:

Reduced DOM Manipulation

DOM operations are slower than JavaScript object operations. React performs comparisons in memory first, reducing direct browser work.

Batched Updates

React groups multiple updates together instead of updating immediately after every state change. This avoids unnecessary rendering cycles.

Efficient Rendering

Only modified elements update, which reduces:

  • Layout recalculations

  • Paint operations

  • Browser rendering overhead

Predictable UI Management

Developers no longer manually synchronize the UI with application state. React handles update optimization automatically.

High-Level React Render → Diff → Commit Flow

React internally follows a structured pipeline.

1. Render Phase

React executes component functions and creates a new Virtual DOM tree.

Example:

<App />

This becomes a fresh Virtual DOM structure. This phase is purely computational. No browser updates happen yet.

2. Diff Phase (Reconciliation)

React compares:

  • Previous tree

  • New tree

It calculates minimal required updates.

3. Commit Phase

React finally updates the Real DOM. Only computed changes are applied. The browser then repaints affected areas.

Conclusion

React’s Virtual DOM is essentially an optimization layer between application logic and the browser DOM.

This render → diff → commit workflow allows React applications to remain efficient, scalable, and easier to maintain.

The Virtual DOM does not eliminate rendering costs entirely, but it dramatically reduces unnecessary work. That balance between developer simplicity and rendering efficiency is one of the main reasons React became widely adopted for modern frontend development.

More from this blog