GIMTEC

Share this post

Building a React-Like Library: Static Virtual DOM

www.gimtec.io

Building a React-Like Library: Static Virtual DOM

Building a React-like library to learn how frontend frameworks works under the hood.

Llorenç Muntaner
Apr 26, 2023
2
Share
Share this post

Building a React-Like Library: Static Virtual DOM

www.gimtec.io

Building a React-Like Library

This is the first of four issues where we build a React-like library to learn how frontend frameworks work under the hood.

The series contains the following articles:

  • Render a static virtual DOM. This article.

  • Functional Components. Upcoming.

  • Implement useState. Upcoming.

  • Implement diffing. Upcoming.

Introduction

HTML is a markup language that defines the structure of a website. The DOM is the representation of the objects defined by the HTML. The browser creates and manages the DOM internally.

Virtual DOM is when this representation lives in the Javascript code.

Note: For more details, I wrote an article on HTML, DOM, Shadow DOM, and Virtual DOM.

Virtual DOM is a pattern many frontend frameworks use to render applications. Understanding the virtual DOM helps us understand the frameworks at a deeper level.

Initial Example

Let’s start with a simple HTML:

<div>
  <h1 id=”title”>Hello, World!</h1>
  <p>I’m learning about virtual DOM</p>
</div>

Below is a tree representation of this HTML:

A representation of this DOM in JS is:

const vDom = {
  tag: "div",
  props: {},
  children: [
    {
      tag: "h1",
      props: { id: "title" },
      children: ["Hello, World!"]
    },
    {
      tag: "p",
      props: {},
      children: ["I’m learning about virtual DOM"]
    }
  ]
};

Render the Virtual DOM

To render this virtual DOM, we’ll need a function that receives this tree as input and manipulates the DOM accordingly.

render(vDom);

We also need to know where to render it. Most single-page applications start with an HTML and an empty div used by the render function. Something like the following:

<html>
  <!-- ... -->
  <body>
    <div id=”root”></div>
    <script src=”./app.js”></script>
  <body>
</html>

It’s the responsibility of app.js to populate the <div id=”root”></div>.

// app.js
const vDom = {...}
render(vDom, document.getElementById(“root”));

Virtual Nodes

Before we implement the render function, we need to understand the data of the virtual DOM.

The previous virtual DOM uses a simple structure to represent an HTML element:

{
  tag: “h1”,
  props: { id: “title” },
  children: ["Hello, World!"]
}
  • “tag”: the tag name of the element, such as “div” or “h1”.

  • “props”: an object with the attributes of the element. For example, { id: ‘title’ }.

  • “children”: the nodes that go between the opening and closing tag in the HTML representation <div>(children)</div>.

A node can also be a string.

“Hello, World!”

With these representations of HTML elements, we have all we need to display them.

The Render Function

Let’s write the render function:

// app.js
const render = (vnode, parent) => {
  // PENDING
}

Node as Object

A node is an object with the tag property:

const render = (vnode, parent) => {
  // create HTML element
  const element = document.createElement(vnode.tag);
}

The attributes are in the props:

const render = (vnode, parent) => {
  // ...
  // set attributes
  if (vnode.props) {
    Object.keys(vnode.props).forEach(key => {
      const value = vnode.props[key];
      element.setAttribute(key, value);
    });
  }
}

Our virtual DOM starts with one node:

{
  tag: “div”,
  props: {},
  children: [...]
}

The rest of the elements are children of this first node. We also need to render them:

const render = (vnode, parent) => {
  // ...
  // iterate over children and render them
  if (vnode.children) {
    // call render recursively
    vnode.children.forEach(child => render(child, element));
  }
}

And finally, we need to append the element we created to the parent.

const render = (vnode, parent) => {
  // ...
  // append the element created
  return parent.appendChild(element);
}

If we run this, we almost get what we want:

<div>
  <h1 id=”title”></h1>
  <p></p>
</div>

Node as String

We still need to manage a last case: when the node is just a string:

children: ["Hello, World!"]

children: ["I’m learning about virtual DOM"]

In both of these cases, the render function is called with the string:

// `child` is just `"Hello, World!"`
vnode.children.forEach(child => render(child, element));

Therefore, we need to add this extra check before we create the element:

const render = (vnode, parent) => {
  // manage string type
  if (typeof vnode === "string") {
    return parent.appendChild(document.createTextNode(vnode));
  }
  // ...
}

If we put it all together, we have the following render function:

const render = (vnode, parent) => {
  // manage string type
  if (typeof vnode === "string") {
    return parent.appendChild(document.createTextNode(vnode));
  }

  // create HTML element
  const element = document.createElement(vnode.tag);

  // set attributes
  if (vnode.props) {
    Object.keys(vnode.props).forEach(key => {
      const value = vnode.props[key];
      element.setAttribute(key, value);
    });
  }

  // iterate over children and render them
  if (vnode.children) {
    vnode.children.forEach(child => render(child, element));
  }

  // append the element created
  return parent.appendChild(element);
};

render(vDom, document.getElementById(“root”));

Simple Single-Page Application

We built a simplified version of how frameworks like React render applications using a virtual DOM.

Find all the code in this gist.

The power of the virtual DOM comes further down the road. Stay tuned for the next article!


Thanks to Sebastià and Michal for reviewing this article 🙏

Share if you like this post!

Share

Don’t forget to subscribe if you want to learn how frontend frameworks work under the hood.

2
Share
Share this post

Building a React-Like Library: Static Virtual DOM

www.gimtec.io
Comments
Top
New
Community

No posts

Ready for more?

© 2023 Llorenç Muntaner
Privacy ∙ Terms ∙ Collection notice
Start WritingGet the app
Substack is the home for great writing