by Brandon Konkle
What is the virtual DOM?
Never mind that, let's play video games!
The browser is the choke point.
Avoid the browser DOM as much as possible.
Where did the idea of a virtual DOM come from?
Facebook released React on May 29th, 2013.
It was created by Jordan Walke, inspired by Facebook's XHP project which was in turn inspired by E4X. Both projects allow you to embed XML within other languages.
Pete Hunt wanted to use it for Instagram, so he refactored it into an open source package.
Their focus was on JSX and reusable components.
The virtual DOM was just a way to make it fast enough to be practical.
How does the virtual DOM work in React?
A component is structured as an ES6 class which implements certain methods - called "lifecycle methods".
- render() - renders the component, must return a React.Element (automatically generated by JSX)
- componentWillMount() - called before the component is "mounted", or takes ownership of an element
- componentDidMount() - called after the component is initially rendered to the element it is mounted to
- shouldComponentUpdate() - called before a component is re-rendered to determine if it should
- componentWillUpdate() - called before a component is re-rendered
- componentDidUpdate() - called after a component is re-rendered
- componentWillUnmount() - called before a component cleans up & removes itself from the element it owns
State is available for each individual component, but not required. External state managers are common.
So, who else is using virtual DOM?
When React started gaining momentum, alternate implementations quickly began to show up.
Ractive was created at The Guardian, mostly before React was announced.
They independently came to the idea of a virtual DOM. Developer Rich Harris of The Guardian blogged:
I distinctly remember reading the post on Hacker News and thinking 'well I may as well give up' – so many of Ractive's ideas, which a day earlier had seemed entirely novel, had already been implemented by a team of engineers with the might of Facebook behind them.
The biggest difference:
Ractive parses your Mustache templates into an intermediate representation of the DOM.
Each instance of Ractive is an independent component, with its own lifecycle.
construct, config, init, render, complete, change, update, unrender, teardown, insert, detach
Two Way Binding
By default, a Ractive instance will update its internal model based on user input, if you have <input>, <textarea> or <select> elements.
This is similar to React's optional "controlled components".
Ractive components expose their data as observables. You can even use wildcards in the keypath.
Mithril is a lightweight full MVC framework with virtual DOM diffing.
- Designed to be familiar to people with server-side MVC framework experience
- Around 7kb gzipped
- Zero dependencies
- Template language that is valid JS uncompiled, compiles down to static objects
- Two-way binding
- Client-side routing
- API client utilities
Which results in a slight performance improvement.
Handles just the virtual DOM, allowing you to do the rest your way.
Which means you must implement your own render mechanics.
- 'h' - allows you to use hyperscript to describe a virtual DOM tree
- 'create-element' - creates a new DOM node from a virtual dom tree
- 'diff' - compares two virtual DOM trees and creates a changeset that can be applied with 'patch'
- 'patch' - updates the DOM with a changeset generated from 'diff'
Elm is a language and a framework.
It was created to embrace functional reactive programming for user interfaces.
- no runtime exceptions!
- static typing
- immutable data
- module system
- structured interop with JS
- uses virtual-dom
Elm includes helpers to make it easier to describe the DOM.
The DOM is converted into a virtual-dom tree.
Since all Elm functions are pure, the same input is guaranteed to result in the same output. This allows the diff calculation to skip over DOM nodes with arguments that haven't changed.
Instead of calling the todoList function on every frame, this example checks to see if state.tasks has changed since last frame. If not, todoList is skipped.
(This is equivalent to comparing props in React's componentShouldUpdate method.)
Deku is a functional re-imagining of React.
It's tiny! ~6kb
The scope is intentionally limited:
- No built-in state management
- No classes or inheritance
- No context or refs
Components are just objects.
They have functions & properties on them. They don't store any state on themselves or use this anywhere.
Use them just like React components, complete with JSX:
Lifecycle callbacks can be set as properties on the component.
- beforeMount, afterMount
- shouldUpdate, beforeUpdate, afterUpdate
- beforeRender, render, afterRender
It analyzes Handlebars templates at compile time, identifying static areas that don't change and dynamic areas that do. Virtual DOM diffing is done against the dynamic areas only.
Internally, instead of creating a virtual DOM, Glimmer builds a tree of streams, each stream pointing to a node in the DOM.
When re-rendering, Glimmer walks the tree and flushes the streams. If the primitive value produced by the stream has not changed, it does nothing.
Like other virtual DOM libraries, Glimmer works by walking the tree, looking for dirty nodes, and revalidating any dirty nodes it finds.
The only difference is how much of the tree is marked dirty before revalidation begins.
With Glimmer, only the dynamic portions of the DOM are marked dirty and revalidated.
This is just the beginning.
Exploring the Virtual DOM
By Brandon Konkle