Virtual DOM

A Virtual DOM (VDOM) is a concept of displaying UI elements on the webpage without coupling them with the Real DOM (DOM). It is a lightweight JavaScript object, a tree structure similar to the DOM. Using libraries like ReactDOM, we align and display the VDOM on the page; which mounts the entire VDOM on a DOM element. This process establishes a single point of connection with the DOM, which helps in the process UI elements change with browsers updating dom with a minimum number of repaint or reflow.

According to the React documentation,

the Virtual DOM (VDOM) is a programming concept where an ideal, or a virtual representation of the UI is kept in the memory and synced with the real DOM with ReactDOM library.

The process of syncing the VDOM with DOM is called reconciliation [discussed later].

Let’s take an example:

class DivElement extends React.Component {
  .
  .
  render () {
    return (<div className="div-class">Hey Div!</div>)
  }
}

JSX: An XML like syntax extension to JavaScript.

In react we can write JSX syntax to create UI elements. The render function [as in the above example] returns a JSX element, React later converts them to HTML elements.

Roughly, the above HTML like codes will become:

React.createElement (
  'div',
  { className: 'div-class'},
  'Hey Div!'
)

This element, a react div element is part of the VDOM. If there would have been another element inside the div, then nested elements would have been the result. For example:

render () {
  return (
    <div className='p-class'>
      <span className='c-class'>
        Nested!
      </span>
    </div>
  )
}

// converts to
React.createElement (
  'div',
  {className: 'p-class'},
  React.createElement (
    'span',
    {className: 'c-class'},
    'Nested'
  )
)

If you see close enough, you should see a nested structure [a tree].

Example: Displaying dynamic data.

class RenderText extends React.Component {
  .
  .
  .
  render () {
    return ( {this.props.text})
  }
}

// use it like this
<RenderText text={"Hello!"} />
<RenderText text={"React"} />
<RenderText text={"Component"} />

Note: props is the read only property passed to a React component.

All such components used in the application are part of the VDOM.

How does VDOM efficiently manipulate the UI Elements?

The first clue here is when using VDOM if there is a change in UI, then the DOM [actual] does not change. And if the DOM does not change, there is no repaint or reflow.

So how do we see the change if the DOM does not change?

Reconciliation

Consider the following UI and change in it.

<div>
  <div>
    View with 2 divs.
  </div>
</div>

+++++++++++++++
Changed to
+++++++++++++++

<span>
  <div>
    View with 1 div inside 1 span.
  </div>
</span>

As we already know, in React a tree represents the UI elements. In this case, when changing the view Reacts sees the difference at the root element. The old one starts with a div element while the new one starts with a span element. Whenever React encounters such case, it recreates everything from the point where it sees a difference/change. In other words, it changes only those nodes of the tree which changes and all the children [nodes] of the sub-tree. 

In the case where only the attributes of the UI elements have changed, React changes only the changed attributes. For example:

<div style={{"color": "red", "fontSize": "14px"}}>Test</div>
+++++++++++++
changed to
+++++++++++++
<div style={{"color": "red", "fontSize": "20px"}}>Test</div>

While changing from old to new element, React only modifies the fontSize attribute.

Let us see another example where only the children will change and, the root will remain the same.

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
<ul>
++++++++++++++++
Add a new item:
++++++++++++++++
<ul>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
<ul>

In this case, as the first two items are the same, there will be no change at that level in the tree. React will add a new item at the end.

Another example where the order of the existing item changes.

<ul>
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

+++++++++++++++
Add a new item:
+++++++++++++++

<ul>
  <li>Item 3</li>
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

The tree of these two views will be entirely different. In the old one, the first node is Item 1 while in the new one, the first node is item 3.

But if we see here, if only we could add a new node [Item 3] above Item 1, we wouldn’t have to recreate Item 1 and 2.

To keep track of such changes, React uses key attribute.

Rewriting the above example with the key attribute:

<ul>
  <li key="item-id-1">Item 1</li>
  <li key="item-id-2">Item 2</li>
</ul>

+++++++++++++++
Add a new item:
+++++++++++++++

<ul>
  <li key="item-id-3">Item 3</li>
  <li key="item-id-1">Item 1</li>
  <li key="item-id-2">Item 2</li>
</ul>

Now while constructing the new tree, React will know that Item 1 and Item 2 are the same items. There is no change in those elements, only one new element [Item 3] has been added in the UI.

For a detailed explanation read: Reconciliation