Skip to content

Commit

Permalink
Properties diff middleware (#382)
Browse files Browse the repository at this point in the history
  • Loading branch information
agubler authored Jun 7, 2019
1 parent 6a72939 commit 02914d1
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 5 deletions.
33 changes: 28 additions & 5 deletions src/core/vdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface WidgetMeta {
nodeMap: Map<string | number, Node>;
destroyMap: Map<string, () => void>;
deferRefs: number;
diffMap: Map<string, (current: any, next: any) => void>;
}

export interface WidgetData {
Expand Down Expand Up @@ -435,7 +436,7 @@ export function tsx(tag: any, properties = {}, ...children: any[]): DNode {
}
}

function diffProperties(current: any, next: any, invalidator: () => void) {
function propertiesDiff(current: any, next: any, invalidator: () => void) {
const propertyNames = [...Object.keys(current), ...Object.keys(next)];
let diffedProperties = [];
for (let i = 0; i < propertyNames.length; i++) {
Expand Down Expand Up @@ -717,6 +718,12 @@ function destroyHandles(destroyMap: Map<string, () => void>) {
destroyMap.clear();
}

function runDiffs(meta: WidgetMeta, current: any, next: any) {
if (meta.diffMap.size) {
meta.diffMap.forEach((diff) => diff({ ...current }, { ...next }));
}
}

export const invalidator = factory(({ id }) => {
const [widgetId] = id.split('-');
return () => {
Expand Down Expand Up @@ -744,6 +751,18 @@ export const node = factory(({ id }) => {
};
});

export const diffProperties = factory(({ id }) => {
return (diff: (current: any, next: any) => void) => {
const [widgetId] = id.split('-');
const widgetMeta = widgetMetaMap.get(widgetId);
if (widgetMeta) {
if (!widgetMeta.diffMap.has(id)) {
widgetMeta.diffMap.set(id, diff);
}
}
};
});

export const destroy = factory(({ id }) => {
return (destroyFunction: () => void): void => {
const [widgetId] = id.split('-');
Expand Down Expand Up @@ -1710,7 +1729,8 @@ export function renderer(renderer: () => RenderResult): Renderer {
children: next.node.children,
nodeMap: new Map(),
destroyMap: new Map(),
deferRefs: 0
deferRefs: 0,
diffMap: new Map()
};
widgetMetaMap.set(next.id, widgetMeta);
widgetMeta.middleware = (Constructor as any).middlewares
Expand Down Expand Up @@ -1801,9 +1821,12 @@ export function renderer(renderer: () => RenderResult): Renderer {
const widgetMeta = widgetMetaMap.get(next.id);
if (widgetMeta) {
widgetMeta.properties = next.properties;
diffProperties(current.properties, next.properties, () => {
widgetMeta.dirty = true;
});
runDiffs(widgetMeta, current.properties, next.properties);
if (!widgetMeta.dirty) {
propertiesDiff(current.properties, next.properties, () => {
widgetMeta.dirty = true;
});
}
if (widgetMeta.dirty) {
next.childrenWrappers = undefined;
didRender = true;
Expand Down
33 changes: 33 additions & 0 deletions tests/core/unit/vdom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import sendEvent from '../support/sendEvent';
import {
create,
renderer,
diffProperties,
defer,
destroy,
getRegistry,
Expand Down Expand Up @@ -3402,6 +3403,38 @@ jsdomDescribe('vdom', () => {
assert.strictEqual(div.outerHTML, '<div><div><div>Hello Bar</div></div></div>');
});
});

describe('diffProperties', () => {
it('Should call diff properties before rendering', () => {
const createWidget = create({ diffProperties, invalidator });
let counter = 0;
const Foo = createWidget(({ middleware }) => {
middleware.diffProperties((current: any, properties: any) => {
assert.deepEqual(current, { key: 'foo' });
assert.deepEqual(properties, { key: 'foo' });
middleware.invalidator();
});
return v('div', [`${counter++}`]);
});
const App = createWidget(({ middleware }) => {
return v('div', [
v('button', {
onclick: () => {
middleware.invalidator();
}
}),
Foo({ key: 'foo' })
]);
});
const r = renderer(() => App({}));
const root = document.createElement('div');
r.mount({ domNode: root });
assert.strictEqual(root.outerHTML, '<div><div><button></button><div>0</div></div></div>');
sendEvent(root.childNodes[0].childNodes[0] as HTMLButtonElement, 'click');
resolvers.resolve();
assert.strictEqual(root.outerHTML, '<div><div><button></button><div>1</div></div></div>');
});
});
});
});
});
Expand Down

0 comments on commit 02914d1

Please sign in to comment.