Ethan
Ethan

Reputation: 35

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.

Upvotes: 1

Views: 4102

Answers (3)

JSRookie
JSRookie

Reputation: 26

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>

Upvotes: 1

Ethan
Ethan

Reputation: 35

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.

Upvotes: 0

Parag Diwan
Parag Diwan

Reputation: 159

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.

Upvotes: 0

Related Questions