loading...
Cover image for The concepts that React tutorials usually skip over

The concepts that React tutorials usually skip over

icncsx profile image DH Kim ・3 min read

Virtual DOM

The vDOM is an in-memory JavaScript representation of the DOM. Just as the DOM is built of nodes, the vDOM is built of virtual nodes (vNodes).

vNodes can be broadly categorized into two types: virtual elements (vElement) or virtual text elements (vText). These virtual nodes can be mapped to respectively the DOM's HTMLElement and TextNode.

What does the virtual DOM look like

A vDOM simply refers to a JavaScript representation of the actual DOM. There is no strict rule on how the virtual DOM should look. For example, we can represent this DOM node...

<p class="emphasis">Hello, world!</p>

as (1) this

const vNode = {
    tagName: "p",
    attrs: {
        className: "emphasis"
    },
    children: ["Hello, world!"]
}

or (2) this

const vNode = {
    type: "p",
    props: {
        className: "emphasis"
    },
    descendents: ["Hello, world!"]
}   

As long as we can find a reliable way to reconstruct the actual DOM using any version of its virtual representation, we are fine.

createElement(type, props, ...children)

Most virtual DOM implementation will have a function called createElement like in React.createElement(). Such a function simply returns a virtual element given some parameters describing what type of element we would like to create.

const createElement = (type, props = {}, ...children) => {
  return {
    type,
    props,
    children,
  };
};

const vApp = createElement(
  "div",
  { className: "app" },
  createElement("p", { className: "emphasis" }, "Hello, world!")
);

If you log vApp, it should look like this:

{
  type: 'div',
  props: { className: 'app' },
  children: [
    {
      type: 'p',
      props: { className: 'emphasis' },
      children: [ 'Hello, world!' ]
    }
  ]
}

vDOM to DOM

The vDOM is a plain JavaScript object, and we cannot magically insert these into the native DOM. The browser needs actual native nodes to display HTML. React uses a render function that expects a vDOM node to be passed as a parameter and it will return a native DOM node that can be inserted or appended to the DOM.

DOM Refresher

The vDOM should have all the details you need to create an equivalent representation in the real DOM. In case you don't remember DOM related methods, I have included them below.


// Creating an element
const $el = document.createElement("h1");

// Setting non-style attributes
$el.className = "emphasis";

// Setting style attributes
$el.style.border = "1px solid black";

// Appending a child element
const textEl = document.createTextNode("Hello, world!"); 
$el.appendChild(textEl)

JSX

If you read official Babel JSX documentation, you’ll know that Babel transpiles this code:

<ul className="list">
  <li>item 1</li>
  <li>item 2</li>
</ul>

into this

React.createElement("ul", { className: "list" },
  React.createElement("li", {}, "item 1"),
  React.createElement("li", {}, "item 2"),
);

We've been doing a similar thing. Instead of React.createElement, we just have createElement. But wouldn't it just be wonderful if we can stop explicitly calling createElement and just write JSX just as you would do in React! Yes, you actually can with a plugin called babel-plugin-transform-react-jsx. Install the plugin using yarn or npm and we can now include a comment-like line called a JSX pragma at the top of our source file:

/** @jsx createElement */
<ul className=”list”>
  <li>item 1</li>
  <li>item 2</li>
</ul>

This is what will tell Babel to transpile the JSX using our createElement function and not React.createElement. After transpiling, we get the following:

createElement(
  "ul",
  { className: "list" },
  createElement(
    "li",
    {},
    "item 1"
  ),
  createElement(
    "li",
    {},
    "item 2"
  )    
);

Rarely if ever will you find the need to create your own createElement function. This is strictly for your reference.

Capitalize your component name

When JSX is being transpiled, Babel uses the case of the tag name to determine if we are describing a component or an HTML element. This is why we always start component names with a capital letter.

Always import React from 'react'

Make sure to import React even if we don't see a reference to React anywhere in our code because remember: JSX ultimately gets converted to a bunch of React.createElement. We need a reference to React.

// do this
import React from 'react';

Hopefully you enjoyed this whirlwind tour of concepts I wish someone had taught me when I was first learning React. Obviously, these details are unimportant to many of you who don't care about the implementation detail. At the very least, I hope you found these concepts informative!

PS: Sometimes it's fun to take a peak under the hood!

Warmly,
DH

Discussion

pic
Editor guide
Collapse
richytong profile image
Richard Tong

A vDOM simply refers to a JavaScript representation of the actual DOM. There is no strict rule on how the virtual DOM should look.

This is one of those things I wish I knew before I cast aside vDOM as a black box sometime earlier in my career. There are some good practices here, great for anyone picking up React. Kudos

Collapse
shakhbulatgaz profile image
Shakhbulat Gazgireev

Amen to that. When I was learning Frontend for the firs timet, I thought that VDOM is just a clean copy of the "real" DOM.

Collapse
gruckion profile image
Stephen Rayner

How does this help me? Could you give 3 examples where this has helped you write better react?

Collapse
icncsx profile image
DH Kim Author

Hi, Stephen! It's true that knowing how an internal combustion engine works doesn't necessarily make you a better driver. But it does certainly help you understand why you should get an oil change or not put regular fuel in a premium-fuel only car.

As for me personally, I like knowing these details about React because they help me with debugging. Knowing that JSX is just a JavaScript object at the end of the day helps me understand that diffing in React-speak is simply the process of comparing two JavaScript objects. Now objects can have many things in them including other objects. When you compare two objects which are reference types, it can be quite tricky for JavaScript to figure out if they are "deeply" equal. This is why you would use immutable data structures when setting state. Otherwise, even if the contents of those objects have changed, React which uses a shallow equality check, would not deem two objects to be unequal.

Collapse
merri profile image
Vesa Piittinen

It is always good to know why you're doing whatever you're doing instead of blindly following a pattern and being like "ok this is magical but it works".

Collapse
icncsx profile image
DH Kim Author

Wow, I didn't know this post would get nearly this much attention. Thank you to all those who checked it out. More content to come~

Collapse
merri profile image
Vesa Piittinen

There are a lot of beginners here as well as people who need the occasional reminder of the basics so just keep on pushing out whatever you think is worth sharing :)

Collapse
provish profile image
Vishal Gupta

Good One.