#2 Virtual DOM - Delightful React

Subscribe to my newsletter and never miss my upcoming articles

In the previous chapter , we learnt about React elements and components and how to render a simple React app using plain HTML.

WMRSG.png

To really convince developers to use a tool, there is that one feature that is so good it makes developers try it immediately, isn't it?

Well, React has tons of amazing features but VirtualDOM is a feature that stands out.

Let's do an experiment

Disclaimer: This is a slightly geeky experiment. 😅 It's totally fine if you don't fully understand what the heck this is. Just follow along and read the VirtualDOM section carefully. Cheers!


To understand VirtualDOM and why it is important, let's do an experiment.

Let's create React elements and update the DOM every 1 second.

Let's modify our script tag, like so. We'll create a function called render, and we will put our hydrate function inside it. And we'll call this render function, every one second using a setInterval.

<!DOCTYPE html>
<html>

  <body>
    <div id="app"></div>

    <script 
      src="https://unpkg.com/react@17.0.1/umd/react.development.js"
    ></script>
    <script 
      src="https://www.unpkg.com/react-dom@17.0.1/umd/react-dom.development.js"
    ></script>
    <script 
      src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"
    ></script>
    <script type="text/babel" data-presets="es2017,react">
      function MyComponent(){
        return <div>
            <h1> Delightful React </h1>
            <p> Let's learn React </p>
          </div>
      }

      function render(){
        window.ReactDOM.hydrate(
          <MyComponent/>, 
          document.getElementById("app")
        );
      }

      setInterval(render, 1000) // render function is called every second

    </script>
  </body>
</html>

This will run the hydrate function once every second. We won't see much of a change with the naked eye but we can see one thing.

React doesn't create duplicate elements even if hydrated multiple times. It only creates a div, a h1 and a p element in the HostRoot. (HostRoot is another name to the DOM node onto which React renders elements. In this case, it is the div with id app).

preview1.png

In other words, each time we hydrate/render elements in React:

  • React ensures that the HostRoot only has the elements that were represented with React elements. (We asked for a h1, a p and a div and that's all we got rendered)
  • It is like painting a frame in a video game. Every frame the game console renders the screen with the elements in the game again but it doesn't duplicate the elements.

Imagine a Mario game. You don't see a new Mario created with every frame do you?

React also works in the same way.


Does that mean that React deletes older elements and recreates the entire tree every render?

Let's answer that comprehensively. Let's create a Javascript script that looks like this. Every second we add elements into the div#app node and we also cleanup just before a new "render" to make sure we don't have any duplicates.

<!DOCTYPE html>
<html>

  <body>
    <div id="app"></div>

    <script 
      src="https://unpkg.com/react@17.0.1/umd/react.development.js"
    ></script>
    <script 
      src="https://www.unpkg.com/react-dom@17.0.1/umd/react-dom.development.js"
    ></script>
    <script 
      src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"
    ></script>
    <script type="text/babel" data-presets="es2017,react">

      function cleanup(){
          // clean up existing elements 
        document.getElementById("app").innerHTML = ""
      }
      function render(){
        cleanup();
        // add elements
        const div = document.createElement("div");
        const h1 = document.createElement("h1")
        h1.textContent = "Delightful React"
        const p = document.createElement("p")
        p.textContent = "Let's learn React"
        div.append(h1)
        div.append(p)
        document.getElementById("app").append(div);        
      }

      setInterval(render, 1000)

    </script>
  </body>
</html>

There, this gives exactly the same output.

preview1.png

As long as we delete all of our old elements and create new ones we should be able to replicate React's behaviour.

Let's compare

Let's look at the performance of both of the HTML files that we created in this tutorial and compare. We can do that using a Chrome DevTool feature called profiling. To profile our app, simply open DevTools in chrome. Then open the Performance tab and click on this button. This will profile the performance of the app/file and give results.

Asset_4.png

I ran the profiling for you and here are the results.

When we profile the file without React in it (the file with our naive cleanup function), this is how the graph looks like.

Asset_3.png

And, this is what the profile of the app with React looks like.

Asset_2.png

There is a stark difference here. Our plain Javascript HTML app creates new nodes every 1 second. But the React app doesn't. It only ever created nodes the first time it rendered. 😮

React + ReactDOM = Efficient

React and ReactDOM don't create new DOM nodes if they don't have to. Creating DOM nodes is not a cheap process on the CPU and React optimises it's rendering in such a way that it only instructs ReactDOM to create/update DOM nodes if it really really has to.

Group_2.png

This is a super small app. It only has 3 elements. Imagine a gigantic app with hundreds of components and thousands of elements. How does React track all those elements and optimise?

Virtual DOM

React internally has an in-memory representation of the DOM nodes. This in-memory representation is called the Virtual DOM.

  • React has an internal representation of the React elements in the Virtual DOM.
  • Inside the Virtual DOM, React maintains information of each React element that is currently rendered on the screen in the form of an object
  • It maintains a list of all the elements in memory in the form a tree of objects.

Each time we try to render the components, React won't just immediately make changes to the DOM because DOM changes are expensive on the CPU. Instead, it computes a new tree in memory, computes the diff across the existing tree and the new tree, which is fast.

Rendering_lists_in_React_Copy_7.png

Finally, it figures out what changes to make, which elements to add, which elements to remove, which elements to modify etc, and then performs those changes on the DOM.

So this way React is very, very clever as it minimises the number of changes in the actual physical DOM nodes.

React renders React elements to DOM elements and also figures out the least computationally expensive way of doing so

React can be used anywhere

React is a very versatile framework.

Just like we are using React and ReactDOM to create DOM elements out of React Elements, React has other packages that it can use to create elements for different platforms. For example, there is ReactNative that React can use to create elements for Android and iOS operating systems.

There is also a community package called ReactInk, that can be used to create elements for the terminal.

And you can also create your own custom glue for the custom platform you are building for your apps. React is simply the brain where the rendering logic takes place. But you can adopt it into any platform you like, as long as you have a custom glue.

React_Native_FInal_Copy_3.png


React is an incredible framework and we are just getting started. Let’s keep going! 🤩 In the next chapter, we will talk about the JSX syntax more and how we can render various kinds of content in our React Elements. Stay tuned!

Comments (2)

Mohd Shad Mirza's photo

Very detailed 👏

Bhargav Ponnapalli's photo

Thank you so much Shad!