Forked from marvinhagemeister/little-vdom-decompiled.js
Created
March 8, 2020 23:55
-
-
Save HamedFathi/0c28e43c04dd584ab2c2549b21be93a8 to your computer and use it in GitHub Desktop.
Jason little-vdom decompiled
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
/* eslint-disable no-unused-vars */ | |
/* eslint-disable no-else-return */ | |
// JSX constructor, similar to createElement() | |
export const h = (type, props, ...children) => { | |
return { | |
type, | |
// Props will be an object for components and DOM nodes, but a string for | |
// text nodes | |
props, | |
children, | |
key: props && props.key | |
}; | |
}; | |
export const render = ( | |
newVNode, | |
dom, | |
oldVNode = dom._vnode || (dom._vnode = {}), | |
currentChildIndex | |
) => { | |
// Check if we are in fact dealing with an array of nodes. A more common | |
// and faster version of this check is Array.isArray() | |
if (newVNode.pop) { | |
return newVNode.map((child, index) => { | |
render( | |
child, | |
dom, | |
oldVNode._normalizedChildren && oldVNode._normalizedChildren[index] | |
); | |
}); | |
} | |
// Check if we have a component. Only functions have a .call() method. | |
// Here components have a different signature compared to Preact or React: | |
// | |
// (props, state, updateFn) => VNode; | |
// | |
// The 3rd argument is basically similar concept-wise to setState | |
else if (newVNode.type.call) { | |
// Initialize state of component if necessary | |
newVNode.state = oldVNode.state || {}; | |
// Add children to props | |
const props = { children: newVNode.children, ...newVNode.props }; | |
const renderResult = newVNode.type( | |
props, | |
newVNode.state, | |
// Updater function that is passed as 3rd argument to components | |
nextState => { | |
// Update state with new value | |
Object.assign(newVNode.state, nextState); | |
return render(newVNode, dom, newVNode); | |
} | |
); | |
return (newVNode.i = render( | |
renderResult, | |
oldVNode.i || dom, | |
(oldVNode && oldVNode.i) || {}, | |
newVNode | |
)); | |
} | |
// Standard DOM elements | |
else { | |
// Create a DOM element and assign it to the vnode. If one already exists, | |
// we will reuse the existing one and not create a new node. | |
newVNode.dom = | |
oldVNode.dom || | |
(newVNode.type | |
? document.createElement(newVNode.type) | |
: // If we have a text node, vnode.props will be a string | |
new Text(newVNode.props)); | |
// diff props | |
if (newVNode.props != oldVNode.props) { | |
// If newVNode.type is truthy (=not an empty string) we have a DOM node | |
if (newVNode.type) { | |
Object.keys(newVNode.props || {}).map(name => { | |
let value = newVNode.props[name]; | |
if ( | |
value != (oldVNode.props && oldVNode.props[name]) && | |
name in newVNode.dom | |
) { | |
return (newVNode.dom[name] = value); | |
} else { | |
return newVNode.dom.setAttribute(name, value); | |
} | |
}); | |
} | |
// Otherwise a text node | |
else { | |
// Update text node content | |
newVNode.dom.data = newVNode.props; | |
} | |
} | |
// insert at position | |
if (oldVNode.dom || currentChildIndex != undefined) { | |
dom.insertBefore(newVNode.dom, dom.childNodes[currentChildIndex + 1]); | |
} | |
// diff children (typed/keyed) | |
newVNode._normalizedChildren = newVNode.children.concat | |
.apply([], newVNode.children) | |
.map((child, index) => { | |
// If we have previous children we search for one that matches our | |
// current vnode | |
const nextOldChild = oldVNode._normalizedChildren | |
? oldVNode._normalizedChildren.find((oldChild, childIndex) => { | |
return ( | |
oldChild && | |
oldChild.type == child.type && | |
oldChild.key == child.key && | |
(childIndex == index && (index = undefined), | |
(oldVNode._normalizedChildren[childIndex] = 0), | |
oldChild) | |
); | |
}) | |
: {}; | |
// Continue diffing recursively against the next child. If the vnode | |
// has no children we assume that we have a string and convert it into | |
// a text vnode. | |
const nextNewChild = child.children || h('', child); | |
render(nextNewChild, newVNode.dom, nextOldChild, index); | |
}); | |
// remove old children if there are any | |
if (oldVNode._normalizedChildren) { | |
oldVNode._normalizedChildren.map(oldChild => { | |
oldChild && oldChild.dom.remove(); | |
}); | |
} | |
Object.assign(oldVNode, newVNode); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment