I'm with you. All this complexity is baffling, when there's a very optimized rendering engine sitting there in the form of the browser, and soon a suitable component model.
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;
});
}
}
}
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
This is a sketch of a raw custom element with no library for sugar. A library that assisted in the pattern would presumably implement the accessors for you.
ES/TypeScript decorators would be an easy way to do this, or just a function that fixes up the class after declaration.
What if your component has a lot of nodes? Do you re-render them all? I guess that's the reason they made react. Even if the state of component changes most of the DOM nodes of render component stays the same and re-rendering them would take too long.
So Aurelia components are web components? I can create one with document.createElement('my-aurelia-component'), and container.appendChild(), and the element will fully work and have it's lifecycle callbacks called?
I tried to look in the documentation, but couldn't see this clearly stated. It looked like Aurelia would have to be in charge of lifecycle to get dependency injection to work. Specifically, custom element constructors are called by the browser with no arguments: how does this work with Aurelia components that expect to receive constructor arguments via dependency injection?
If this really creates a Web Component, how does `this.http` ever get set? The browser will call the constructor with no arguments.
What exactly gets passed to `document.registerElement()` (for the v0 Custom Elements API) or `customElements.define()` (for the v1 Custom Elements API)? Are you saying that Aurelia generates and registers a separate custom element class? That's not in the docs. If so, how does that element find the instances to inject into the user-defined constructors?
The main issue that talks about custom element support is still open, and the answer really does seem to be that Aurelia can't create custom elements: https://github.com/aurelia/framework/issues/7
This unfortunately seems to confirm that Aurelia uses the terminology of Web Components, but doesn't actually use or create real Web Components.
That link you just posted is not contained in any of the docs or links that either you or I posted above. I can't actually find it in the entire documentation hub, so even if I did "read the docs", how was I supposed to find it?
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:
edit: example uses. In a template: When the parent component renders and sets `foo`, the child will schedule a task to re-render.In JS: