Skip to content

Commit 35619a0

Browse files
committed
Add reconciliation logic
1 parent 6f5fdb7 commit 35619a0

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

src/reconciler.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,43 @@ export function render(element, container) {
1010

1111
function reconcile(parentDom, instance, element) {
1212
if (instance == null) {
13+
// Create instance
1314
const newInstance = instantiate(element);
1415
parentDom.appendChild(newInstance.dom);
1516
return newInstance;
17+
} else if (element == null) {
18+
// Remove instance
19+
parentDom.removeChild(instance.dom);
20+
return null;
21+
} else if (instance.element.type === element.type) {
22+
// Update instance
23+
updateDomProperties(instance.dom, instance.element.props, element.props);
24+
instance.childInstances = reconcileChildren(instance, element);
25+
instance.element = element;
26+
return instance;
1627
} else {
28+
// Replace instance
1729
const newInstance = instantiate(element);
1830
parentDom.replaceChild(newInstance.dom, instance.dom);
1931
return newInstance;
2032
}
2133
}
2234

35+
function reconcileChildren(instance, element) {
36+
const dom = instance.dom;
37+
const childInstances = instance.childInstances;
38+
const nextChildElements = element.props.children || [];
39+
const newChildInstances = [];
40+
const count = Math.max(childInstances.length, nextChildElements.length);
41+
for (let i = 0; i < count; i++) {
42+
const childInstance = childInstances[i];
43+
const childElement = nextChildElements[i];
44+
const newChildInstance = reconcile(dom, childInstance, childElement);
45+
newChildInstances.push(newChildInstance);
46+
}
47+
return newChildInstances.filter(instance => instance != null);
48+
}
49+
2350
function instantiate(element) {
2451
const { type, props } = element;
2552

test/03.reconciliation.test.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import test from "ava";
2+
import browserEnv from "browser-env";
3+
/** @jsx createElement */
4+
import { render, createElement } from "../src/didact";
5+
6+
// Create document global var
7+
browserEnv(["document"]);
8+
9+
test.beforeEach(t => {
10+
let root = document.getElementById("root");
11+
if (!root) {
12+
root = document.createElement("div");
13+
root.id = "root";
14+
document.body.appendChild(root);
15+
}
16+
t.context.root = root;
17+
});
18+
19+
test("replace div to span", t => {
20+
const root = t.context.root;
21+
let element = <div>Foo</div>;
22+
render(element, root);
23+
t.is(root.innerHTML, "<div>Foo</div>");
24+
const prevChild = root.firstElementChild;
25+
element = <span>Foo</span>;
26+
render(element, root);
27+
t.is(root.innerHTML, "<span>Foo</span>");
28+
const nextChild = root.firstElementChild;
29+
t.not(prevChild, nextChild);
30+
});
31+
32+
test("reuse div", t => {
33+
const root = t.context.root;
34+
let element = <div>Foo</div>;
35+
render(element, root);
36+
t.is(root.innerHTML, "<div>Foo</div>");
37+
const prevChild = root.firstElementChild;
38+
element = <div>Bar</div>;
39+
render(element, root);
40+
t.is(root.innerHTML, "<div>Bar</div>");
41+
const nextChild = root.firstElementChild;
42+
t.is(prevChild, nextChild);
43+
});

0 commit comments

Comments
 (0)