What is the virtual DOM in React?

The virtual DOM is an in-memory representation of the UI. React diffs it against the previous version and only applies the minimal set of real DOM updates needed.

React

Overview

Direct DOM manipulation is slow because every change can trigger reflow and repaint. React keeps a lightweight virtual DOM (a plain JavaScript object tree mirroring the real DOM) in memory. When state changes, React renders a new virtual DOM, diffs it against the previous one (reconciliation), and applies only the changed nodes to the real DOM.

Key Points

  • •The virtual DOM is not a real browser API - it is a React concept (a plain JS object tree).
  • •Reconciliation: React's algorithm for computing the minimal diff between two virtual DOM trees.
  • •React batches multiple state updates and processes them in a single re-render pass.
  • •The `key` prop helps React identify which list items moved, were added, or removed during reconciliation.
  • •React Fiber (React 16+) is the new reconciliation engine - it can pause, prioritise, and resume rendering work.

Examples

What JSX compiles to (the virtual DOM object)

typescript
// JSX you write
const element = <button className="btn" onClick={handleClick}>Click me</button>;

// What Babel compiles it to
const element = React.createElement(
  'button',
  { className: 'btn', onClick: handleClick },
  'Click me'
);

// Which creates a plain JS object like:
// {
//   type: 'button',
//   props: { className: 'btn', onClick: handleClick, children: 'Click me' }
// }

How state updates lead to minimal DOM patches

tsx
function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <h1>Count: {count}</h1>   {/* only this text node changes */}
      <button onClick={() => setCount(c => c + 1)}>+</button>
    </div>
  );
}
// When count changes, React re-renders the component (virtual DOM),
// diffs the new tree against the old one, and updates only the
// text node inside <h1> - not the whole div or the button.

Keys help React track list items across re-renders

tsx
// Without key (or with index key): React may reuse wrong DOM nodes
{items.map((item, i) => <Row key={i} data={item} />)}

// With stable key: React correctly identifies each row
{items.map(item => <Row key={item.id} data={item} />)}

Pro Tip

The virtual DOM is an implementation detail - you rarely need to think about it directly. What matters practically: keep renders cheap (avoid heavy computation in the render function), use `React.memo` for expensive child components, and always use stable keys in lists.