Skip to content

Instantly share code, notes, and snippets.

@asolove
Created March 26, 2017 19:21
Show Gist options
  • Save asolove/e6166a8872a184c6c6c05fca8ebe4ed6 to your computer and use it in GitHub Desktop.
Save asolove/e6166a8872a184c6c6c05fca8ebe4ed6 to your computer and use it in GitHub Desktop.
preact-innerDiffNode
/** Apply child and attribute changes between a VNode and a DOM Node to the DOM.
* @param {Element} dom Element whose children should be compared & mutated
* @param {Array} vchildren Array of VNodes to compare to `dom.childNodes`
* @param {Object} context Implicitly descendant context object (from most recent `getChildContext()`)
* @param {Boolean} mountAll
* @param {Boolean} absorb If `true`, consumes externally created elements similar to hydration
*/
function innerDiffNode(dom, vchildren, context, mountAll, absorb) {
let originalChildren = dom.childNodes,
children = [],
keyed = {},
keyedLen = 0,
min = 0,
len = originalChildren.length,
childrenLen = 0,
vlen = vchildren && vchildren.length,
j, c, vchild, child;
if (len) {
for (let i=0; i<len; i++) {
let child = originalChildren[i],
props = child[ATTR_KEY],
key = vlen ? ((c = child._component) ? c.__key : props ? props.key : null) : null;
if (key!=null) {
keyedLen++;
keyed[key] = child;
}
else if (hydrating || absorb || props || child instanceof Text) {
children[childrenLen++] = child;
}
}
}
if (vlen) {
for (let i=0; i<vlen; i++) {
vchild = vchildren[i];
child = null;
// if (isFunctionalComponent(vchild)) {
// vchild = buildFunctionalComponent(vchild);
// }
// attempt to find a node based on key matching
let key = vchild.key;
if (key!=null) {
if (keyedLen && key in keyed) {
child = keyed[key];
keyed[key] = undefined;
keyedLen--;
}
}
// attempt to pluck a node of the same type from the existing children
else if (!child && min<childrenLen) {
for (j=min; j<childrenLen; j++) {
c = children[j];
if (c && isSameNodeType(c, vchild)) {
child = c;
children[j] = undefined;
if (j===childrenLen-1) childrenLen--;
if (j===min) min++;
break;
}
}
}
// morph the matched/found/created DOM child to match vchild (deep)
child = idiff(child, vchild, context, mountAll);
if (child && child!==dom) {
if (i>=len) {
dom.appendChild(child);
}
else if (child!==originalChildren[i]) {
if (child===originalChildren[i+1]) {
removeNode(originalChildren[i]);
}
dom.insertBefore(child, originalChildren[i] || null);
}
}
}
}
if (keyedLen) {
for (let i in keyed) if (keyed[i]) recollectNodeTree(keyed[i]);
}
// remove orphaned children
while (min<=childrenLen) {
child = children[childrenLen--];
if (child) recollectNodeTree(child);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment