React Virtual DOM vs Real DOM

Devinder Suthwal
Devinder
Published in
5 min readNov 30, 2020

If you landed here then you have an idea that React uses Virtual DOM for better performance and want to have better understanding of it. In this article we will try to find out what is DOM and its problem, what is Virtual DOM, how it solves DOM’s problems and how React uses Virtual DOM.

What is DOM?

“The W3C Document Object Model (DOM) is a platform and language-neutral interface that allows programs and scripts to dynamically access and update the content, structure, and style of a document.”

The DOM is an abstraction of a page’s HTML structure. It takes HTML elements and wraps them in an object with a tree-structure — maintaining the parent/child relationships of those nested HTML elements. This provides an API that allows us to traverse nodes (HTML elements) and manipulate them in a number of ways — such as adding nodes, removing nodes, editing a node’s content, etc.

DOM inefficiency

DOM was originally intended for static UIs — pages rendered by the server that don’t require dynamic updates. When the DOM updates, it has to update the node as well as re-paint the page with its corresponding CSS and layout. Say we have an array.

let fruits = [‘Apple’, ‘Orange’, ‘Banana’]

We want to update here from Orange to lemon. Then we need to create a new array.

let fruits = [‘Apple’, ‘Lemon’, ‘Banana’]

In an efficient way we can just traverse to the fruits[2] and update only this element.

Now it’s common to have a thousands node in a single SPA. So repaint the whole page for each change is very-very expensive.

Ideally, we’d like to only re-render items that receive updates, leaving the rest of the items as-is.

Knowing when to update

There are a couple of ways in which components can tell when a data update occurs and whether or not it needs to re-render to the UI:

  • Dirty Checking (slow) — Checks through all node’s data at a regular interval to see if there have been any changes. This is inefficient because it requires traversing every single node recursively to make sure it’s data isn’t “dirty” (out of date). This was used in AngularJS 1.x.
  • Observable (fast) — Components are responsible for listening to when an update takes place. Since the data is saved on the state, components can simply listen to events on the state and if there is an update, it can re-render to the UI. React uses it.

Virtual DOM

The Virtual DOM is a light-weight abstraction of the DOM. You can think of it as a copy of the DOM, that can be updated without affecting the actual DOM. It has all the same properties as the real DOM object, but doesn’t have the ability to write to the screen like the real DOM. The virtual DOM gains it’s speed and efficiency from the fact that it’s lightweight. In fact, a new virtual DOM is created after every re-render.

Reconciliation is a process to compare and keep in sync the two files (Real and Virtual DOM). Diffing algorithm is a technique of reconciliation which is used by React.

Is the Shadow DOM the same as the Virtual DOM?

No, they are different. The Shadow DOM is a browser technology designed primarily for scoping variables and CSS in web components. The virtual DOM is a concept implemented by libraries in JavaScript on top of browser APIs.

How does updates work in React?

  • On the first load, ReactDOM.render() will create the Virtual DOM tree and real DOM tree.
  • As React works on Observable patterns, when any event(like key press, left click, api response, etc.) occurred, Virtual DOM tree nodes are notified for props change, If the properties used in that node are updated, the node is updated else left as it is.
  • React compares Virtual DOM with real DOM and updates real DOM. This process is called Reconciliation. React uses Diffing algorithm techniques of Reconciliation.
  • Updated real DOM is repainted on browser.

Additional points regarding updates.

  • Virtual DOM is pure JS file and light weight, So capturing any update in Virtual DOM is much faster than directly updating on Real DOM.
  • React takes a few milliseconds before reconciliation. This allows react to bundle few processes. This increases efficiency and avoids unnecessary reprocessing. Because of this delay we should not rely on this.state.val just after setState().
  • React does shallow comparison of props value. We need to handle deep comparison separately, immutable is the most common way to handle it.

Reconciliation

React compares the Virtual DOM with Real DOM. It finds out the changed nodes and updates only the changed nodes in Real DOM leaving the rest nodes as it is. This process is called Reconciliation.

Generic Reconciliation methods have complexity of O(n3) . Normally we have thousands of nodes in any application. This will be too expensive to use generic methods.

React implements a heuristic O(n) algorithm based on two assumptions:

  1. Two elements of different types will produce different trees.
  2. The developer can hint at which child elements may be stable across different renders with a key prop.

In practice, these assumptions are valid for almost all practical use cases.

Diffing Algorithm

React first compares the two root elements. The behavior is different depending on the types of the root elements.

React compared the root DOM Elements Types.

  • Elements of different types: Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. Going from <a> to <img>, or from <Article> to <Comment>, or from <Button> to <div> — any of those will lead to a full rebuild. This will lead to component unmount and mount lifecycle calls too.
  • DOM Elements Of The Same Type: When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM node, and only updates the changed attributes.After handling the DOM node, React then recurses on the children. This will lead to component update lifecycle calls.

Why key should be used in lists?

By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and generates a mutation whenever there’s a difference.

Old

<ul>

<li>first</li>

<li>second</li>

</ul>

New

<ul>

<li>first</li>

<li>second</li>

<li>third</li>

</ul>

Here React will add a third element directly. But if the order changes then react gets confused in comparing. To overcome this key is introduced.

<ul>

<li key=”2015">Duke</li>

<li key=”2016">Villanova</li>

</ul>

Updated list.

<ul>

<li key=”2014">Connecticut</li>

<li key=”2015">Duke</li>

<li key=”2016">Villanova</li>

</ul>

Here react will identify the component with key and update only the changed items.

Keys should be stable, predictable, and unique. Unstable keys (like those produced by Math.random()) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.

We don’t recommend using indexes for keys if the order of items may change. This can negatively impact performance and may cause issues with component state.

--

--