I started a project based on LitElement There are many components nested in each other, Let us say we have this structure:
the root component is my-app
import { LitElement, html, customElement, query } from 'lit-element';
import './my-form';
import './my-view';
import { MyView } from './my-view';
@customElement('my-app')
export class MyApp extends LitElement {
@query('my-view') private myView?: MyView;
private handleCountChange(e: CustomEvent<{ count: number }>) {
if (!this.myView) throw 'my-view not found!';
this.myView.count = e.detail.count;
}
render() {
return html`
<my-form @countChanged=${this.handleCountChange}></my-form>
<my-view></my-view>
`;
}
}
as you see we have two components: my-form
import { LitElement, html, customElement, property } from 'lit-element';
@customElement('my-form')
export class MyForm extends LitElement {
@property({ type: Number }) count: any = 0;
private updateCount(e: KeyboardEvent) {
this.count = (<HTMLInputElement>e.target).value;
this.dispatchEvent(
new CustomEvent('countChanged', {
composed: true,
bubbles: true,
cancelable: true,
detail: { count: this.count }
})
);
}
render() {
return html`
<input value=${this.count} @input=${this.updateCount} type="text" />
`;
}
}
and my-view:
import { LitElement, html, customElement, property } from 'lit-element';
@customElement('my-view')
export class MyView extends LitElement {
@property({ type: Number }) count: number = 0;
render() {
return html`
<p>${this.count}</p>
`;
}
}
To get the property count
changes from my-form
into my-view
I dispatched event listener then used it at my-app
then at handleCountChange
I'm assigning the count
value to MyView
which imported as a class in addition to import it as a componet.
Currently, this works, but I feel it is a long way especially when I have more nested components. I would like to know if there is a better for doing that.
Is there something similar to Context API
which exists at react.js
I thought about using redux
but somebody didn't recommend it with litElemnt.
One of the ideas I'm thinking is to dispatch the event to document
instead of the current component, but maybe this is a bad practice! What are your suggestions, please let me know?
you have probably resolve this issue, but I can send you how I would deal with this.
You need to lift your state up to your my-app
component. This state will be a single source of truth and deliver count
value to my-form
and my-view
child components.
In my-app
component, you can change handleCountChange
to something like this (in case, if you define count
as an attribute and let my-app
to receive initial value from attributes):
private handleCountChange(e: CustomEvent<{ count: number }>) {
this.setAttribute('count', count); // If you set `count` as observed attribute, you will not need to call `requestUpdate` method
}
or like this, if you define count
as class property
private handleCountChange(e: CustomEvent<{ count: number }>) {
this.count = count;
this.requestUpdate(); // force to call render method which is necessary in this case
}
Note that, you will have to send count
value also to the my-form
component. It will work also without it, but if you will do it, you will lost single source of truth of your state and that can cause potential unexpected behaviour.
If you will need to send an example, please let me know.