Skip to content

Instantly share code, notes, and snippets.

@asolove
Created March 26, 2017 19:21
Show Gist options
  • Select an option

  • Save asolove/e6166a8872a184c6c6c05fca8ebe4ed6 to your computer and use it in GitHub Desktop.

Select an option

Save asolove/e6166a8872a184c6c6c05fca8ebe4ed6 to your computer and use it in GitHub Desktop.

Revisions

  1. asolove created this gist Mar 26, 2017.
    93 changes: 93 additions & 0 deletions 0-innerDiffNode.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,93 @@
    /** 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);
    }
    }