JSFiddle - React, Tailwind, and code Playground
by gothic
HTML
<button id="reload">RELOAD</button>
<div id="root"></div>
CSS
#root {
border: 1px solid black;
padding: 10px;
margin: 30px 0 0 0;
}
JavaScript
function h(type, props, ...children) {
return {
type,
props,
children
};
}
function createElement(node) {
if (typeof node === 'string') {
return document.createTextNode(node);
}
const $el = document.createElement(node.type);
node.children.map(createElement).forEach($el.appendChild.bind($el));
return $el;
}
function changed(node1, node2) {
return typeof node1 !== typeof node2 || typeof node1 === 'string' && node1 !== node2 || node1.type !== node2.type;
}
function updateElement($parent, newNode, oldNode, index = 0) {
if (!oldNode) {
$parent.appendChild(createElement(newNode));
} else if (!newNode) {
$parent.removeChild($parent.childNodes[index]);
} else if (changed(newNode, oldNode)) {
$parent.replaceChild(createElement(newNode), $parent.childNodes[index]);
} else if (newNode.type) {
const newLength = newNode.children.length;
const oldLength = oldNode.children.length;
for (let i = 0; i < newLength || i < oldLength; i++) {
updateElement($parent.childNodes[index], newNode.children[i], oldNode.children[i], i);
}
}
}
const a = h(
'ul', {
'class': 'list'
},
h(
'li',
null,
'item 1'
),
h(
'li',
null,
'item 2'
)
);
const b = h(
'ul', {
'class': 'list'
},
h(
'li',
null,
'item 1'
),
h(
'li',
null,
'hello!'
)
);
const $root = document.getElementById('root');
const $reload = document.getElementById('reload');
updateElement($root, a);
$reload.addEventListener('click', () => {
updateElement($root, b, a);
});