Skip to content

Instantly share code, notes, and snippets.

@Tevinthuku
Last active August 14, 2019 16:34
Show Gist options
  • Save Tevinthuku/2e05e1d65f7ef3d6dcd6ef0d54688055 to your computer and use it in GitHub Desktop.
Save Tevinthuku/2e05e1d65f7ef3d6dcd6ef0d54688055 to your computer and use it in GitHub Desktop.
reconciliation happenning
import { updateDomProperties } from "./dom-utils";
import { TEXT_ELEMENT } from "./element";
let rootInstance = null; // will keep the reference to the instance rendered on the dom
export function render(element, parentDom) {
const prevInstance = rootInstance;
const nextInstance = reconcile(parentDom, prevInstance, element);
rootInstance = nextInstance;
}
function reconcile(parentDom, instance, element) {
if (instance == null) {
// initial render
const newInstance = instantiate(element);
parentDom.appendChild(newInstance.dom);
return newInstance;
} else if (element == null) {
/**
* this section gets hit when
* a childElement was previously present
* but in the new element is not present
* for instance a todo item that has been deleted
* it was present at first but is now not present
*/
parentDom.removeChild(instance.dom);
return null;
} else if (instance.element.type === element.type) {
/**
* if the types are the same
* eg: if prevType was "input" and current type is still "input"
* NB:// we still havent updated
* the props of the node rendered in the dom
*/
instance.childInstances = reconcileChildren(instance, element);
instance.element = element;
return instance;
} else {
/**
* if the type of the previous Instance is not the
* same as the type of the new element
* we replace the old with the new.
* eg: if we had an "input" and now have "button"
* we get rid of the input and replace it with the button
*/
const newInstance = instantiate(element);
parentDom.replaceChild(newInstance.dom, instance.dom);
return newInstance;
}
}
function instantiate(element) {
const { type, props } = element;
const isTextElement = type === TEXT_ELEMENT;
const dom = isTextElement
? document.createTextNode("")
: document.createElement(type);
updateDomProperties(dom, props);
// Instantiate and append children
const childElements = props.children || [];
// we are recursively calling instanciate on each
// child element
const childInstances = childElements.map(instantiate);
const childDoms = childInstances.map(childInstance => childInstance.dom);
childDoms.forEach(childDom => dom.appendChild(childDom));
const instance = { dom, element, childInstances };
return instance;
}
function reconcileChildren(instance, element) {
const dom = instance.dom;
const childInstances = instance.childInstances;
const nextChildElements = element.props.children || [];
const newChildInstances = [];
const count = Math.max(childInstances.length, nextChildElements.length);
for (let i = 0; i < count; i++) {
const childInstance = childInstances[i];
const childElement = nextChildElements[i];
// the reconcile function has logic setup to handle the scenario when either
// the child instance or the childElement is null
const newChildInstance = reconcile(dom, childInstance, childElement);
newChildInstances.push(newChildInstance);
}
return newChildInstances.filter(instance => instance != null);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment