You want to learn React, VueJS, Svelte, Angular,… super fast ?! You are in the right place !
Or you are loosing your head to choose a JS framework because you are facing the endless framework war ?
All those frameworks have really common concepts, this is why:
- The hardcore way: Read all the docs & read all source code & contribute to the project
- The hard way: Learn pure JavaScript, DOM API, Browser API and reverse engineer framework core concepts
- The common way: Pick any of these framework and practice it a lot.
With Vanilla JS
Understanding React & VueJS: Virtual DOM
To make a Virtual DOM, we must understand what is the DOM itself ?
We know that the DOM contains HTML nodes.
So what is composed a HTML node ?
- A tag: div, span, p, h1,…
- Attributes: class, id, label, value,…
- Children HTML nodes: Contains zero, one or more HTML nodes.
Ok let’s recreate the DOM itself in JavaScript (alias Virtual DOM).
First we need to create a function representing an HTML Node
function createVirtualNode(tag, attributes, childrenNodes) {
tag = tag || '';
attributes = attributes || {};
childrenNodes = childrenNodes || [];
return {
tag,
attributes,
childrenNodes,
};
}
Let’s determine the HTML structure we want to build:
<div id="header">
<p>Hello <span class="bold text-pink">everybody</span> !</p>
<img
src="https://images.unsplash.com/photo-1600505386060-16d02c5626c3"
alt="man cooking"
style="width: 300px;"
/>
</div>
Ok let’s use our function createVirtualNode to represent this structure.
Analyze the following carefully.
const virtualDOM = createVirtualNode('div', { id: 'header' }, [
createVirtualNode('p', {}, [
'Hello ',
createVirtualNode('span', { class: 'bold text-pink' }, ['everybody']),
' !',
]),
createVirtualNode('img', {
src: 'https://images.unsplash.com/photo-1600505386060-16d02c5626c3',
alt: 'man cooking',
style: 'width: 300px;',
}),
]);
console.dir(virtualDOM, { depth: null });
Let’s see what our virtual DOM looks like:
{
tag: 'div',
attributes: { id: 'header' },
childrenNodes: [
{
tag: 'p',
attributes: {},
childrenNodes: [
'Hello ',
{
tag: 'span',
attributes: { class: 'bold text-pink' },
childrenNodes: [ 'everybody' ]
},
' !'
]
},
{
tag: 'img',
attributes: {
src: 'https://images.unsplash.com/photo-1600505386060-16d02c5626c3',
alt: 'man cooking'
},
childrenNodes: []
}
]
}
Whoow… that’s beautiful… right ?
But but what do we do now with this structure ? They are 2 big uses:
- Render it to the real DOM !
- Generating the corresponding HTML server-side and send an HTML page
Let’s render it to the real DOM first by creating the render function:
function renderDOMNode({ tag, attributes, childrenNodes }) {
const node = document.createElement(tag);
for (const attributeKey in attributes) {
node.setAttribute(attributeKey, attributes[attributeKey]);
}
for (const childrenNode of childrenNodes) {
if (typeof childrenNode === 'string') {
node.appendChild(document.createTextNode(childrenNode));
} else {
node.appendChild(renderDOMNode(childrenNode));
}
}
return node;
}
Let’s use it !
const node = renderVirtualNode(virtualDOM);
document.getElementById('app').appendChild(node);
HTML Preview:
function renderDOMNodeStr({ tag, attributes, childrenNodes }) {
let node = `<${tag}`;
for (const attributeKey in attributes) {
node += ` ${attributeKey}="${attributes[attributeKey]}"`;
}
if (childrenNodes.length === 0) {
node += '/>';
} else {
node += '>';
for (const childrenNode of childrenNodes) {
if (typeof virtualChildNode === 'string') {
node += virtualChildNode;
} else {
node += renderDOMNodeStr(childrenNode);
}
}
node += `</${tag}>`;
}
return node;
}
If we build a library for our VirtualDOM, it will look like this !
Now let’s see how to use our VirtualDOM server side:
Sources