-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Composability via component nesting #8
Comments
@nodefish thanks so much for the info in this post. It's great to see a few of us are coming to the same conclusions here, and again I really appreciate you sharing your experience. As luck would have it, I've been thinking on this same problem recently also, and basically have the same as you've proposed unstaged locally. As I've been toying with the notion of taking inspiration from The way I envisage this working is effectively this:
class Component extends HyperComponent {
render () {
return this.html`<div>${[
this.slot(ChildComponent),
this.slot(ChildComponent, 'named-slot'),
this.slot(ChildComponent, 'call-render').render(...args)
this.slot(ChildComponent, 'call-constructor')(...args),
this.slot(ChildComponent, 'call-constructor-and-render')(...args).render(...args)
]}</div>`
}
} The nice thing about an interface like this, is we'll be able to abstract caching component instances with basically a Would love to hear you thoughts on the above. cc/ @WebReflection |
Sounds promising. One of my concerns (in general, not specific to your approach) is adding overhead to nesting child elements in the parent template because we should be able to have thousands of child elements (e.g. in a dynamic list), but your approach seems lean enough. What's the rationale behind exposing the nested component's constructor? Perhaps standardizing the constructor is the way to go, in which case we don't need to expose it, i.e. it just needs Another random thing that comes to mind which may or may not be helpful: in other frameworks, the Nested tag function render() {
return this.html`
<div id="parent">
${this.child(ChildClass, props, null)}
</div>
`
} Nested tag with transclusion function render() {
return this.html`
<div id="parent">
${this.child(ChildClass, props, ['<div>', this.child(AnotherChildClass, OtherProps, null), '</div>])}
</div>
`
} As in, in the parent scope (depth 0), we are adding a nested element (depth 1) with its own nested element inside it (depth 2), all defined from the parent scope. We could somewhat equivalently have defined the depth 2 component (nested within the nested component) in the definition of the depth 1 component - but then we lose the ability to dynamically set this from the parent scope (useful sometimes). This is equivalent to the innerHTML property but for custom tags, e.g. [slot / yield] Essentially, this is heavily drawing from React internals and the |
That's a really good point which I hadn't considered fully I think in order to adopt a Which given your above examples could effectively result in the following API: class Parent extends HyperComponent {
function render () {
return this.html`<div id="parent">${
this.child(Child, { id: 'child1' }, this.wire(':child')`<div>${[
this.child(Child, { id: 'subchild1' }, `<div>woah!</div>`),
this.child(Child, { id: 'subchild2' }, `<div>dude!</div>`)
]}</div>`)
}</div>`
}
}
class Child extends HyperComponent {
function render () {
if (typeof this.props.children === 'string') {
return this.html`<div id="${ this.props.id }"> ${this.props.children} </div>`
}
return this.html`<div id="${ this.props.id }">${
this.props.children
}</div>`
}
}
Edit: Updated example to illustrate passing different types as Edit Edit: Updated the |
I still have a couple of blind spots in my understanding of wires, but this looks pretty good to me! I have a suspicion some quirks are going to appear at some point during actual usage, but nonetheless this looks like the right direction. |
@nodefish ah-ha! I just realised managing wires with Because wires can now be bound to the same object via an id we can simply have |
Awesome!
I wasn't sure what was the best thing to be doing with the wires here. They're essentially persistent document fragments, and there are a lot of options for what to do with them. I was thinking since we want
Really happy to share ideas on this, as this is quite challenging to navigate but the possibilities are pretty exciting. |
Hrmmm, I'm not entirely sure the @nodefish did you happen to see the latest in #7, I've just pushed a working draft of what we've discussed above. Would love feedback if you're able. |
I just gave my feedback on the draft. It's looking good and I can't think of much to say. It's pretty much what I think it should be at this stage. Need to test it to be able to say more. Is it stable enough to give it a try? Re: wire: you could be right! I didn't realize it was just an arbitrary id. |
type can be 'html' or 'svg' or 'async' , by default is 'html'. Type can contain any ':id' which is used to weakly relate a wired content to the same context. 'html:any-id' is the same as ':any-id', the colon is there just to delimit type from I'd. Type is needed mostly to figure out how the wire will be used: some HTML content, some svg which require different handling, some async content which will be resolved at distance and it will figure out if where it's resolved should be HTML or svg. |
Understood. I've read the hyperHTML docs but I need to get my hands dirty to truly understand it, as it's a lot to take in (and the writing style is a bit erratic :) ) |
I just need time to write a better documentation. Right now the situation is too poor |
No worries, it's a huge amount of stuff and I'm surprised you did it all on your own in the first place. |
* v3 Refactor * Update docs * Add browser alias viperhtml->hyperhtml * Add API for managing child components #8 * Add setState API * Update wire interface to allow shorthand named wire creation * Remove WIP adopt API * Update examples in readme * Remove svg method * Update documentaion Closes: #5 * Add build step * add package-lock.json * v3 re-refactor * Update docs
I'm going to close this one off, as the API discussed here made it's way into v3 via |
I was working on a class-based library for hyperHTML but this project beat me to the punch, so I figure I may drop my work and just share notes with you.
The main difficulty I've encountered in experimenting with hyperHTML is composability, which is the entire purpose of the component based approach.
There needs to be an easy way to declare nested components. It's trivial if the nested components are already instantiated; you'd be able to do the following in the parent's render function:
The above is only possible if the child element is already declared and instantiated. In React, this is not an issue because child elements are automatically identified and rendered via
React.createElement
(JSX transpiles tocreateElement
), which instantiates and then tracks the child elements in its VDOM tree upon rendering. But if there's no VDOM and no createElement, then something is certainly missing!Proposal:
I think the leanest approach here is a
hypercomponent.prototype.child
function that wraps the render function provided byhyperHTML.wire
and augments it in the following way:render
output of a child componentHypothetical example of what this would look like:
hypercomponent.prototype.child
akathis.child
would basically create an instance of typeChildClass
and return its render output directly in the parent's render template.Starting from the first render pass,
this.children
would contain references to any nested components.Does this make sense?
The text was updated successfully, but these errors were encountered: