typescriptstenciljsstencil-component

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:

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

Thanks in advance.


Solution

  • The name of the property in the child component is selectedFeature but the parent component is passing its value as selected-feature, which is interpreted as a HTML-attribute and not a Stencil property. Hence, the property will never change and the child won't re-render.

    Change the line accordingly and it should work:

    <child slot="content" selectedFeature={this.selectedFeature}></child>