The concepts that React tutorials usually skip over
Tags: react, javascript, tutorial
Published: 2020-07-10 08:07:40

### 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...

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

as (1) this

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

or (2) this

```js
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.

```javascript
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:

```javascript
{
  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.

```javascript

// 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:

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

into this

```jsx
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](https://www.gatsbyjs.org/blog/2019-08-02-what-is-jsx-pragma/) at the top of our source file:

```jsx
/** @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:

```jsx
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.

```js
// 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