-
-
Notifications
You must be signed in to change notification settings - Fork 113
connected/disconnected events cannot dispatch to nested components #198
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
Comments
…to nested components
are you suggesting the order should be inverted ? good catch btw |
btw, beside the possible typo in the example, the non closing class ParentComponent extends hyper.Component
{
render(){
return this.html`
<div>
${
/* a new component every single render */
new ChildComponent()
}
</div>
`;
}
} If the parent gets its render method invoked twice, you'll have two ChildComponent and one of them probably lost somewhere. As you can see in this Code Pen, you can find ways to setup your instances once instead: const {Component} = hyperHTML;
class ChildComponent extends Component {
constructor() {
super().times = 0;
}
render() {
return this.html`<p>child rendered ${++this.times}</p>`;
}
}
class ParentComponent extends Component {
get hyper() {
// setup some property
this.writable = 123;
// or setup via descriptors ...
return Object.defineProperties(this, {
// ... more own properties
childComponent: {value: new ChildComponent},
// ... and then ...
// shadow hyper getter for the next render
hyper: {get() { return this.html; }}
}).html;
}
render() {
// childComponent is always same one => force its rendering
return this.hyper`<div>${this.childComponent.render()}</div>`;
}
}
const parent = new ParentComponent;
const render = hyperHTML(document.body);
// parent is always same one => force its rendering
setInterval(() => render`${parent.render()}`, 1000); |
Hi @WebReflection, The example code I write is just dummy code. What I really use is something like this: import {Component} from 'hyperhtml/esm';
import diff from 'deep-diff';
class BaseComponent extends Component {
constructor(props) {
super(props);
this.props = props;
this.children = new WeakMap();
this.innerState = this.toState(props);
}
get defaultState() {
return this.innerState;
}
apply(props) {
// convert the props to states
const state = this.toState(props);
// diff the original state and the new state
const changes = diff.diff(this.innerState, state);
if (changes) {
// apply the change to the state object. This would keep the state as the same
changes.forEach(c => diff.applyChange(this.innerState, state, c));
}
this.setState(this.innerState);
}
/**
* toState is the method you can map the properties to inner state
*/
toState(props) {
return typeof props === 'function' ? props : Object.assign({}, props);
}
child(ChildComponent, identity, props_) {
let childComponent = this.children.get(identity);
const props = props_ ? props_ : identity;
if (!childComponent) {
childComponent = new ChildComponent(props);
this.children.set(identity, childComponent);
} else {
childComponent.update(props);
}
return childComponent;
}
/**
* update component properties. It would trigger rerender
*/
update(props) {
if (props) this.props = props;
this.apply(this.props);
}
};
class MenuItem extends BaseComponent {
constructor(props) {
super(props);
}
render() {
return this.html`
<li>${this.state.name}</li>
`;
}
}
class Menu extends BaseComponent {
constructor(props) {
super(props);
}
render() {
return this.html`
<div>A simple menu</div>
<ul>
${this.state.items.map(item => this.child(MenuItem, item))}
</ul>
`;
}
}
const menu = new Menu({items: [{name: 'item 1'}, {name: 'item 2'}, {name: 'item 3'}]});
render(document.querySelector('.simple'))`${menu}`;
setTimeout(() => {
menu.update({items: [{name: 'item 4'}, {name: 'item 5'}, {name: 'item 6'}]});
}, 5000); The BaseComponent extended from hyper Component is trying to solve 2 problems:
Do you think it's a good practice? |
Unfortunately that's true. I'm still trying to figure out how/what would be the best way to solve the issue.
I think you're entering in reversed vDOM world there 😄 Room for improvements I'm trying to ship I want to solve two issues:
Even if unrelated, both seems to be the biggest weakness of If you have any suggestion I'd be happy to listen and, to be honest, I like a lot your |
@liming I just had some weird thoughts on this ... what if ... const components = new WeakMap;
const setChildren = component => {
const children = new WeakMap;
components.set(component, children);
return children;
};
const setChild = (Class, children, identity) => {
const child = new Class;
children.set(identity, child);
return child;
}
// hyper.Component plus a .for(...) static method
class Component {
static for(component, identity) {
const children = components.get(component) || setChildren(component);
return children.get(identity) || setChild(this, children, identity);
}
} So that you could do the following class MenuItem extends Component {
update(props) {
this.setState(props);
return this;
}
render() {
return this.html`
<li>${this.state.name}</li>
`;
}
}
class Menu extends Component {
update(props) {
this.setState(props);
return this;
}
render() {
return this.html`
<div>A simple menu</div>
<ul>
${this.state.items.map(
item => MenuItem.for(this, item).update(item)
)}
</ul>
`;
}
} That would allow you to do something like: const menu = new Menu().update({
items: [{name: 'item 1'}, {name: 'item 2'}, {name: 'item 3'}]
});
render(document.querySelector('.simple'))`${menu}`;
setTimeout(() => {
menu.update({items: [{name: 'item 4'}, {name: 'item 5'}, {name: 'item 6'}]});
}, 5000); What do you think? Would a |
fix #198: connected/disconnected events cannot dispatch to nested component
This problem happened when the the parent of nested components has already bind connected/disconnected events.
In this circumstance, the child component won't receive the onconnected event.
The cause of this is this piece of code. The parent component dispatches onconnect and skips the dispatch of child component.
The text was updated successfully, but these errors were encountered: