'Stencil rerender children with updated prop values

I want a parent component to manage a central state of the application and pass down the relevant information to its children, re-rendering them as needed. This is how I understood parent/child communication in Stencil - the parents send data to the children via properties and the children send data to the parent via events. Is this assumption wrong?

I am having trouble finding a relevant example online that does not reference React-specific API's

Edit: It may be relevant that, in my case, the parent is rendering a wrapper component with a slot. Code sample updated to reflect that...

Simplified Example:

parent.tsx:

// Parent Component
import { Component, State, Listen, h } from '@stencil/core';

@Component({
  tag: 'parent',
  styleUrl: 'parent.css',
})
export class Parent {
  @State() selectedFeature: any = null;

  @Listen('featureClicked', { target: 'body' })
  updateSelectedFeature(e: CustomEvent) {
    this.selectedFeature = e.detail;
  }

  render() {
    return [
      <wrapper>
        <child slot="content" selected-feature={this.selectedFeature}></child>
      </wrapper>,
      // ...other components
    ];
  }
}

child.tsx:

// Child Component
import { Component, Prop, h } from '@stencil/core';

@Component({
  tag: 'child',
  styleUrl: 'child.css',
})
export class Child {
  @Prop() selectedFeature!: any;

  render() {
    if (!this.selectedFeature) return null;

    return (
      <ul>
        {
          Object.entries(this.selectedFeature.attributes)
            .map((key, val) => <li>{key}: {val}</li>)
        }
      </ul>
    );
  }
}

When a new feature is clicked, I want the child component to display it. Currently, I can't make that happen unless:

  • I pass a valid feature on the first render (in which it renders correctly once)
  • Have a listener within the child to catch the selected feature from the DOM

Is there a way to do this without the child listening for events?

Thanks in advance.



Solution 1:[1]

Your assumption is right. Pass down the state via props and emit events and have listeners to listen to these events.

Props are immutable within component but if you wish to make it mutable, stencil provides

 @Prop({ mutable: true }) propertyThatIsMutable;

Also check

@Prop({ reflect: true }) propToReflect; // will reflect as a attribute in DOM.

Solution 2:[2]

I found a workaround suitable for my needs, which is to use @stencil/store.

Docs: https://stenciljs.com/docs/stencil-store

Example: https://github.com/ionic-team/stencil-store/tree/master/test-app

Components that are dependent on this state will re-render on state change, which is nice.

Not marking this as solved, since it does not address the original problem.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Parag Diwan
Solution 2 Ethan