liveBook · Manning

Virtual DOM

As explained in Build a Frontend Web Framework (From Scratch)

An in-memory representation of a user interface tree that a framework associates with rendered HTML and updates dynamically.

Updating a page by hand means mixing application logic with instructions for changing browser nodes. A virtual DOM lets you describe what the view should look like instead. It is a lightweight JavaScript tree that represents the browser’s DOM; it is not the browser’s DOM itself. A framework uses that description to create the view and, when it changes, decide which browser nodes need updating. Not every framework uses this approach. section 3.2 section 1.3.2

Each object in the tree is a virtual node. An element node records its tag, properties, and children; a text node records text; and a fragment groups nodes without adding a parent element. Child order matters. Properties can include attributes and event handlers, even though handlers added programmatically do not appear in HTML markup. section 3.2 section 3.4

{
  type: 'element',
  tag: 'form',
  props: { action: '/login', class: 'login-form' },
  children: [
    {
      type: 'element',
      tag: 'input',
      props: { type: 'text', name: 'user' }
    },
    {
      type: 'element',
      tag: 'input',
      props: { type: 'password', name: 'pass' }
    },
    {
      type: 'element',
      tag: 'button',
      props: { on: { click: () => login() } },
      children: [
        {
          type: 'text',
          value: 'Log in'
        }
      ]
    }
  ]
}

The login-form tree shows how plain objects retain the form’s attributes, ordered inputs, button text, and click handler. section 3.2

To build a small virtual DOM:

  • Give each node a type: text, element, or fragment. section 3.4
  • Create elements with h(tag, props, children). Use hString() for text and hFragment() for a group without a parent element. section 3.5 section 3.9
  • Write component functions that receive state and return virtual nodes. Compose smaller functions to describe larger views. section 3.8.1 section 3.8.3

A list that follows state

A function can return h('ul', {}, todos.map(todo => h('li', {}, [todo]))). Pass it two to-do descriptions and it describes a list with two items. When the state gains an item, call the function again to produce a new tree. The framework renders the tree into browser nodes and updates those nodes to reflect the change. section 3.8.2 section 1.3.2

Updating does not require rebuilding the entire browser view. A reconciliation algorithm compares the old and new virtual trees to find changes such as modified attributes, changed text, or an added node, then applies the needed changes to the DOM. For server-rendered HTML, hydration instead begins by matching existing HTML elements to virtual nodes and attaching event handlers. section 7.2.1 section 1.3.3

How Build a Frontend Web Framework (From Scratch) covers it

How deep it goes
Builds virtual-node helpers and component trees, then works through differences between old and new trees without claiming production completeness.
Examples
Uses a login-form object tree, state-driven to-do lists, and an old-versus-new tree comparison.
What it assumes
Assumes familiarity with basic JavaScript and HTML while defining the browser DOM, virtual nodes, and their relationship.
What you can do after
Build it from scratch with JavaScript node helpers and component functions, then evaluate how changed trees guide DOM updates.
How it connects
Connects virtual nodes to components, application state, DOM reconciliation, and server-rendered HTML hydration.

Also explained in

Compare how 2 books explain virtual DOM →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build a Frontend Web Framework (From Scratch). The section links point to the parts of the book it draws on.