If you wire up your components so that you just re-render the components that have data changes, you get the benefits of dom diffing, without having to diff.
You can skip all this framework JS, and just directly write an async-rendering Web Component. It's pretty compact and easy to understand. I just wrote up a sketch that would work with one of the incremental-dom-based template libraries:
class AsyncWebComponent extends HTMLElement {
constructor() {
super();
this.isLayoutValid = true;
this.attachShadow({mode: 'open'});
this._foo = 'bar';
}
// Accessors could be generated with decorators or a helper library
set foo(value) {
this._foo = value;
// You could check for deep equality before invalidating...
this.invalidate();
}
get foo() {
return this._foo;
}
connectedCallback() {
this.invalidate(); // trigger the initial render
}
render() {
// Call into template library to re-render component.
// If the template is incrementally updated (say with incremental-dom),
// then only child components with data that changes will be updated.
templateLib.render(this.template, this.shadowRoot);
}
invalidate() {
if (this.isLayoutValid) {
this.isLayoutValid = false;
// scheduleRenderTask enqueues tasks, so they'll be run in order down the component tree
// A simple and correct scheduler is to just enqueue a microtask with Promise.resolve().then(task)
scheduleRenderTask(() => {
this.render();
this.isLayoutValid = true;
});
}
}
}
edit: example uses. In a template: <async-web-component foo="[[foo]]"></async-web-component>
When the parent component renders and sets `foo`, the child will schedule a task to re-render.In JS:
let e = document.querySelector('async-web-component');
e.foo = 'baz'; // e schedules a task to re-render
e.foo = 'qux'; // e doesn't schedule a task, because one is pending