Skip to content

Commit

Permalink
Add incremental reconciliation (Didact Fiber)
Browse files Browse the repository at this point in the history
  • Loading branch information
pomber committed Oct 18, 2017
1 parent ab2b562 commit 6174a22
Show file tree
Hide file tree
Showing 10 changed files with 382 additions and 144 deletions.
22 changes: 7 additions & 15 deletions src/component.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
import { reconcile } from "./reconciler";
import { scheduleUpdate } from "./reconciler";

export class Component {
constructor(props) {
this.props = props;
this.props = props || {};
this.state = this.state || {};
}

setState(partialState) {
this.state = Object.assign({}, this.state, partialState);
updateInstance(this.__internalInstance);
scheduleUpdate(this, partialState);
}
}

function updateInstance(internalInstance) {
const parentDom = internalInstance.dom.parentNode;
const element = internalInstance.element;
reconcile(parentDom, internalInstance, element);
}

export function createPublicInstance(element, internalInstance) {
const { type, props } = element;
const publicInstance = new type(props);
publicInstance.__internalInstance = internalInstance;
return publicInstance;
export function createInstance(fiber) {
const instance = new fiber.type(fiber.props);
instance.__fiber = fiber;
return instance;
}
74 changes: 57 additions & 17 deletions src/dom-utils.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,66 @@
export function updateDomProperties(dom, prevProps, nextProps) {
const isEvent = name => name.startsWith("on");
const isAttribute = name => !isEvent(name) && name != "children";
import { TEXT_ELEMENT } from "./element";

const isEvent = name => name.startsWith("on");
const isAttribute = name =>
!isEvent(name) && name != "children" && name != "style";
const isNew = (prev, next) => key => prev[key] !== next[key];
const isGone = (prev, next) => key => !(key in next);

export function updateDomProperties(dom, prevProps, nextProps) {
// Remove event listeners
Object.keys(prevProps).filter(isEvent).forEach(name => {
const eventType = name.toLowerCase().substring(2);
dom.removeEventListener(eventType, prevProps[name]);
});
Object.keys(prevProps)
.filter(isEvent)
.filter(key => !(key in nextProps) || isNew(prevProps, nextProps)(key))
.forEach(name => {
const eventType = name.toLowerCase().substring(2);
dom.removeEventListener(eventType, prevProps[name]);
});

// Remove attributes
Object.keys(prevProps).filter(isAttribute).forEach(name => {
dom[name] = null;
});
Object.keys(prevProps)
.filter(isAttribute)
.filter(isGone(prevProps, nextProps))
.forEach(name => {
dom[name] = null;
});

// Set attributes
Object.keys(nextProps).filter(isAttribute).forEach(name => {
dom[name] = nextProps[name];
});
Object.keys(nextProps)
.filter(isAttribute)
.filter(isNew(prevProps, nextProps))
.forEach(name => {
dom[name] = nextProps[name];
});

// Set style
prevProps.style = prevProps.style || {};
nextProps.style = nextProps.style || {};
Object.keys(nextProps.style)
.filter(isNew(prevProps.style, nextProps.style))
.forEach(key => {
dom.style[key] = nextProps.style[key];
});
Object.keys(prevProps.style)
.filter(isGone(prevProps.style, nextProps.style))
.forEach(key => {
dom.style[key] = "";
});

// Add event listeners
Object.keys(nextProps).filter(isEvent).forEach(name => {
const eventType = name.toLowerCase().substring(2);
dom.addEventListener(eventType, nextProps[name]);
});
Object.keys(nextProps)
.filter(isEvent)
.filter(isNew(prevProps, nextProps))
.forEach(name => {
const eventType = name.toLowerCase().substring(2);
dom.addEventListener(eventType, nextProps[name]);
});
}

export function createDomElement(fiber) {
const isTextElement = fiber.type === TEXT_ELEMENT;
const dom = isTextElement
? document.createTextNode("")
: document.createElement(fiber.type);
updateDomProperties(dom, [], fiber.props);
return dom;
}
Loading

0 comments on commit 6174a22

Please sign in to comment.