Create your own virtual DOM to understand it (Part 1)

In this article I want to recap my experience creating own “virtual DOM”. Sounds too ambitiously? Probably, but it is not that complicated as you might think. As the title states, it will make sense when you create your own, rather than reading thousands of articles about it.

Originally, I was inspired by the talk of stefan judis at Web Rebels 2018, so feel free to take a look at it here.

This concept of Virtual DOM got popular back in 2013 when React was released. Because of this concept ReactJS is one of super fast libraries for building UI. I’ll try to explain it in few sentences, then we will get to writing own one.

Virtual DOM is the representation of DOM as an object. When changes to state of application are made, new Virtual DOM is compared(applying **diffing algorithms**) with DOM and only changes are reflected, not causing full re-rendering of DOM.

Ok, here is a plan how we will create our virtual DOM.

  1. Create *hyperscript *function to render DOM — it is kinda JSX
  2. Create simple app with hyperscript
  3. Make our App dynamic and learn to render virtual DOM
  4. Implement diffing algorithm to see the power of virtual DOM

HyperScript implementation

If you ever worked with ReactJS you probably know what is JSX. It can be another topic for discussion, but shortly it transforms “HTML-like” syntax into JavaScript function calls, in React it is transferred as React.createElement. So, in this step our aim is to *recreate *this awesome function.

Generally, it is the building block that creates virtual DOM. However, in this step I want to emphasize how we can build simple DOM with it and in further steps we will develop it to make virtual DOM.

The inputs for this function are: *type of node, properties(a.k.a. attributes), children. *So here is a simple implementation of this function:

Implementation of **hyperscript **function, that constructs DOM given nodeName, attrs and children

Firstly, It simply creates DOM element with *nodeName. *Secondly, sets its attributes, and last step to append child nodes with the check for text nodes.

Note: actually, we could go further and render children recursively, but I left this for later for simplicity reason.

Here is how it can be used(from now on we will use *h *instead of hyperscript):

Simple app that renders h1 element
Result of calling App() function

Creating application with Hyperscript

Okay, we now can create simple application with the help of Hyperscript. Let’s create a bit more complex application than it was in previous step. Here is our newer App function.

"Complex application" with hyperscript

When the App is executed it creates a div, with two children: one rendering H1 heading, and the second one unordered list. Note that we pass props to our function and render props.list into unordered list. Let’s add some more rendering magic:

Render the app with the state

Generally, we just want to render the output of App function(that is valid DOM) into the body of document giving the state that contains emojis list.

Result of our work

It wasn’t that hard. Is it? Let’s add some dynamic content, and add random emoji every 1 second this way we can see how our app renders.

DOM is fully re-rendering every 1 second

Implement vDOM rendering

Okay, now we have dynamic app done with hyperscript let’s move on to actual virtual DOM and its implementation. First of all we need to change our hyperscript function. Now it should not create real DOM, but instead it rather should create virtual DOM. So, given nodeName, attributes and children we just a create an object with corresponding keys. Thanks to ES6 we can do this in one line:

hyperscript function that returns virtual DOM

We have a virtual DOM and if we execute the App function with same emojis list we get something like this(logged in console):

"Virtual DOM" of out application

Pretty similar to DOM. Now let’s create a function that renders virtual DOM into real DOM. As you might have guessed it should take virtual Node as a parameter. Here it is:

This function renders real DOM(DOM Node) given virtual DOM(Node)

Let me explain what it does step by step:

  1. Using destructuring we retrieve nodeName, attributes and children of virtual Node
  2. If vnode is text(we can check it by vnode.split) then we return text Node
  3. Otherwise we create an element with nodeName and set its attributes from attributes object
  4. Do the same thing for children if any

Now, remember our render function that rendered our App? We just need to change a little bit to make it work:

This article became a bit longer than I thought, so I decided to break into two parts.

So, let’s recap this. We created a hyperscript — virtual DOM factory, renderNodethat turns virtual DOM into DOM element and a function component App that creates whole page. The result is now the same as we did it before without virtual DOM, but now we have more control. In the next article we will explore what makes React(and virtual DOM) so fast.

You can look up all steps in my GitHub repository. You can find these steps in branches.

In the next article we will implement simple diffing algorithm, that will make our app faster and you’ll be able to see it action.

Sign Up to stay up to date in FrontEnd and JavaScript world