Skip to main content
The Virtual DOM (VDOM) is a lightweight JavaScript representation of the actual DOM. Preact uses it to efficiently determine what changes need to be made to the real DOM.

What is a VNode?

A VNode (Virtual Node) is Preact’s internal representation of a DOM element or component. Here’s how VNodes are created (src/create-element.js:47):

VNode structure

Each VNode contains:
  • type - The element type (string for DOM elements, function for components)
  • props - The element’s properties and attributes
  • key - A unique identifier for efficient list diffing
  • ref - A reference to the actual DOM node or component instance
  • _children - Child VNodes
  • _dom - The corresponding real DOM node
  • _component - The component instance (for component VNodes)
  • _parent - The parent VNode
  • _depth - Depth in the VNode tree
Properties prefixed with _ are internal to Preact and should not be accessed directly.

How the Virtual DOM works

Preact’s Virtual DOM operates in three phases:
  1. Render - Components return VNodes describing what the UI should look like
  2. Diff - Preact compares the new VNode tree with the previous one
  3. Commit - Only the differences are applied to the real DOM

The diff algorithm

The diff algorithm is the heart of Preact’s Virtual DOM. It’s implemented in src/diff/index.js:58:

Diffing components

When diffing components, Preact determines whether to reuse an existing instance or create a new one (src/diff/index.js:100):
Preact differentiates between class and functional components by checking if prototype.render exists.

Diffing children

Child diffing is optimized using keys and a skew-based algorithm (src/diff/children.js:45):

Key-based reconciliation

Keys help Preact identify which items have changed, been added, or removed in lists:
Without keys, Preact may re-render all items even if only one changed.
Never use array indices as keys if the list can be reordered. This can cause incorrect updates and poor performance.

Finding matching VNodes

Preact’s diff algorithm uses a sophisticated matching strategy (src/diff/children.js:400):
This algorithm optimizes for common cases like insertions, deletions, and reorderings.

Efficient updates

Preact’s Virtual DOM provides several performance benefits:

Batched updates

Multiple state changes are batched together into a single DOM update:

Minimal DOM manipulation

Only the parts of the DOM that actually changed are updated:

Smart component updates

Components can skip unnecessary renders using shouldComponentUpdate():

Committing changes

After diffing, Preact commits the changes to the real DOM (src/diff/index.js:406):
This phase:
  1. Applies refs to DOM nodes
  2. Invokes lifecycle callbacks (like componentDidMount)
  3. Handles errors gracefully
The commit phase is synchronous and cannot be interrupted, ensuring the DOM is always in a consistent state.