Last active
July 23, 2018 17:46
-
-
Save taylorlapeyre/e47883ea405b3056a133c00a6642ca12 to your computer and use it in GitHub Desktop.
React if jsx was actually just arrays like ["h1", "Hello World"]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Ops = { | |
CREATE: "CREATE", | |
UPDATE: "UPDATE", | |
DELETE: "DELETE", | |
KEEP: "KEEP" | |
}; | |
function constructTree(dom) { | |
if (dom.nodeType === document.TEXT_NODE) { | |
return dom.textContent; | |
} else { | |
const tag = dom.tagName.toLowerCase(); | |
const body = dom.childNodes; | |
const children = []; | |
for (const child of body) { | |
children.push(constructTree(child)); | |
} | |
return [tag, ...children]; | |
} | |
} | |
function reconcile(newTree, existingTree) { | |
if (!newTree && existingTree) { | |
return { | |
op: Ops.DELETE | |
}; | |
} else if (newTree && !existingTree) { | |
if (Array.isArray(newTree)) { | |
return { | |
op: Ops.CREATE, | |
type: newTree[0], | |
children: newTree | |
.slice(1) | |
.map(newChild => reconcile(newChild, undefined)) | |
}; | |
} else { | |
return { | |
op: Ops.CREATE, | |
type: "TEXT", | |
children: newTree | |
}; | |
} | |
} else { | |
if (Array.isArray(newTree) && !Array.isArray(existingTree)) { | |
return { | |
op: Ops.UPDATE, | |
type: newTree[0], | |
children: newTree | |
.slice(1) | |
.map(newChild => reconcile(newChild, undefined)) | |
}; | |
} else if (!Array.isArray(newTree)) { | |
return { | |
op: Ops.UPDATE, | |
type: "TEXT", | |
children: newTree | |
}; | |
} else { | |
const [newType, ...newChildren] = newTree; | |
const [existingType, ...existingChildren] = existingTree; | |
const pairedChildren = Array( | |
Math.max(newChildren.length, existingChildren.length) | |
) | |
.fill() | |
.map((_, index) => { | |
const existingChild = | |
index < existingChildren.length | |
? existingChildren[index] | |
: undefined; | |
const newChild = | |
index < newChildren.length ? newChildren[index] : undefined; | |
return { newChild, existingChild }; | |
}); | |
if (newType !== existingType) { | |
return { | |
op: Ops.UPDATE, | |
type: newType, | |
children: pairedChildren.map(({ newChild, existingChild }) => | |
reconcile(newChild, existingChild) | |
) | |
}; | |
} else { | |
return { | |
op: Ops.KEEP, | |
type: newType, | |
children: pairedChildren.map(({ newChild, existingChild }) => | |
reconcile(newChild, existingChild) | |
) | |
}; | |
} | |
} | |
} | |
} | |
function commit(operation, dom) { | |
if (operation.op === Ops.CREATE) { | |
let element; | |
if (operation.type === "TEXT") { | |
element = document.createTextNode(operation.children); | |
} else { | |
element = document.createElement(operation.type); | |
for (const nextOp of operation.children) { | |
commit(nextOp, element); | |
} | |
} | |
return element; | |
} | |
if (operation.op === Ops.UPDATE) { | |
if (operation.type === "TEXT") { | |
return document.createTextNode(operation.children); | |
} else { | |
const childNodes = dom.childNodes; | |
dom.replaceWith(document.createElement(operation.type)); | |
for (const [index, nextOp] of operation.children.entries()) { | |
const child = commit(nextOp, childNodes[index]); | |
console.log(child); | |
if (child) { | |
dom.appendChild(child); | |
} | |
} | |
} | |
return dom; | |
} | |
switch (operation.op) { | |
case Ops.DELETE: { | |
return null; | |
} | |
case Ops.KEEP: { | |
const childNodes = Array.from(dom.childNodes); | |
for (const [index, nextOp] of operation.children.entries()) { | |
const child = commit(nextOp, childNodes[index]); | |
if (childNodes[index]) { | |
dom.replaceChild(child, childNodes[index]); | |
} else if (child) { | |
dom.appendChild(child); | |
} | |
} | |
return dom; | |
} | |
} | |
} | |
function render(newTree, container) { | |
const existingTree = constructTree(container); | |
const operation = reconcile(newTree, existingTree); | |
commit(operation, container); | |
} | |
render( | |
[ | |
"section", | |
["div", ["p", "Information bout"]], | |
["h1", "hii"], | |
["h2", "I'm subtitle"] | |
], | |
document.getElementById("root") | |
); | |
render( | |
[ | |
"section", | |
["div", ["p", "Information bout"]], | |
["h1", "byee"], | |
["h2", "I'm subtitle"] | |
], | |
document.getElementById("root") | |
); | |
window.render = render; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment