Skip to content

Commit

Permalink
Add reconciliation logic
Browse files Browse the repository at this point in the history
  • Loading branch information
pomber committed May 22, 2017
1 parent 6f5fdb7 commit 35619a0
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/reconciler.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,43 @@ export function render(element, container) {

function reconcile(parentDom, instance, element) {
if (instance == null) {
// Create instance
const newInstance = instantiate(element);
parentDom.appendChild(newInstance.dom);
return newInstance;
} else if (element == null) {
// Remove instance
parentDom.removeChild(instance.dom);
return null;
} else if (instance.element.type === element.type) {
// Update instance
updateDomProperties(instance.dom, instance.element.props, element.props);
instance.childInstances = reconcileChildren(instance, element);
instance.element = element;
return instance;
} else {
// Replace instance
const newInstance = instantiate(element);
parentDom.replaceChild(newInstance.dom, instance.dom);
return newInstance;
}
}

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];
const newChildInstance = reconcile(dom, childInstance, childElement);
newChildInstances.push(newChildInstance);
}
return newChildInstances.filter(instance => instance != null);
}

function instantiate(element) {
const { type, props } = element;

Expand Down
43 changes: 43 additions & 0 deletions test/03.reconciliation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import test from "ava";
import browserEnv from "browser-env";
/** @jsx createElement */
import { render, createElement } from "../src/didact";

// Create document global var
browserEnv(["document"]);

test.beforeEach(t => {
let root = document.getElementById("root");
if (!root) {
root = document.createElement("div");
root.id = "root";
document.body.appendChild(root);
}
t.context.root = root;
});

test("replace div to span", t => {
const root = t.context.root;
let element = <div>Foo</div>;
render(element, root);
t.is(root.innerHTML, "<div>Foo</div>");
const prevChild = root.firstElementChild;
element = <span>Foo</span>;
render(element, root);
t.is(root.innerHTML, "<span>Foo</span>");
const nextChild = root.firstElementChild;
t.not(prevChild, nextChild);
});

test("reuse div", t => {
const root = t.context.root;
let element = <div>Foo</div>;
render(element, root);
t.is(root.innerHTML, "<div>Foo</div>");
const prevChild = root.firstElementChild;
element = <div>Bar</div>;
render(element, root);
t.is(root.innerHTML, "<div>Bar</div>");
const nextChild = root.firstElementChild;
t.is(prevChild, nextChild);
});

0 comments on commit 35619a0

Please sign in to comment.