Skip to content
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

child component doesn't re-render when the property is modified by the parent #899

Closed
1 of 6 tasks
dvolp opened this issue Feb 18, 2020 · 4 comments
Closed
1 of 6 tasks

Comments

@dvolp
Copy link

dvolp commented Feb 18, 2020

Live Demo

https://stackblitz.com/edit/lit-element-t3yobz

Description

Let's say i have a parent component and a child component.

  • I place the child component inside the parent's html.
  • The child component has a property title inside the static get properties() object.
  • In the parent component, i assign the child component's title property to a private variable that is not in the static get properties() of the parent component.
  • Later, in a setTimeout inside the parent component, i change the value of the private variable.
//inside parent component
render(){
 return html`
   <child-component title="${this._privateVariable}"></child-component>
 `
}

constructor(){
 super();
 this._privateVariable = 'lore ipsum'

 setTimeout(()=>{
  this._privateVariable = '123455667'
 }, 10000)
}
  • The child component doesn't re-render.

I'm not sure what should happen in this situation. Since the child component is already watching the title property, my guess is that it should see the value change and re-render even when inside the parent template.

If this is not the case, and I need to manually re-render the parent html, i would love to know why and how to do it correctly:

  • Call requestUpdate() manually?
  • Set a private property in the static get properties() method of the parent component, and pass that property to the child component?

Are there other better solutions to this problem?

Thanks

Steps to Reproduce.

  1. Create parent component.
  2. Create child component with a title property.
  3. Place child component inside the parent html.
  4. In the parent component, assign a private variable to the title attribute of the child component.
    es. <child-component title="${this._privateVariable}"></child-component>
  5. Somewhere later, in the parent component, change the value of the private variable.

Expected Results

The child component should see the property has changed and re-render accordingly.

Actual Results

The child component does not re-render, unless manually calling requestUpdate() from the parent component, or unless the private property is placed in the object returned by LitElement static get getProperty() method of the parent component.

Browsers Affected

  • Chrome
  • Firefox
  • Edge
  • Safari 11
  • Safari 10
  • IE 11

Versions

  • lit-element: 2.2.1
  • lit-htm: 1.1.2
  • webcomponents: 2.2.4
@daKmoR
Copy link
Contributor

daKmoR commented Feb 18, 2020

why do you not want to _title to static get properties?
that is the place to tell it... "hey if any of those change rerender" (all the other js class properties do not tigger an automatic rerender)

@justinfagnani
Copy link
Contributor

Yeah, this is working as intended. The only properties that will automatically trigger a re-render are those listed in static properties. You can list "private" properties there too, you'll probably just want to set attribute: false.

@dvolp
Copy link
Author

dvolp commented Feb 19, 2020

why do you not want to _title to static get properties?
that is the place to tell it... "hey if any of those change rerender" (all the other js class properties do not tigger an automatic rerender)

Yeah, this is working as intended. The only properties that will automatically trigger a re-render are those listed in static properties. You can list "private" properties there too, you'll probably just want to set attribute: false.

@justinfagnani @daKmoR
You missed my point.

If the child component is already watching his title property, shouldn't it realize that the value assigned to it changed, and re-render accordingly?

I don't understand why i have to re-render the whole parent to make the child re-render.

Using the developer console:

  • If i change the child component's property with javascript, the child re-renders perfectly fine, without me having to re-render the whole parent element.

  • If i edit the child component's html and manually change the attribute, the child re-renders perfectly fine, without me having to re-render the whole parent element.

I'm probably missing something, and i would like to know what.

@justinfagnani
Copy link
Contributor

@dvolp the child component is observing its title property, but it's not observing the parent component's _privateVariable property. And without declaring _privateVariable as a LitElement property in the static properties object, the parent component isn't observing that property either.

You need to re-render the parent when you set _privateVariable because re-rendering is what sets the child's title property to the current value of _privateVariable.

The binding in here only runs on a render. If this isn't run, there's nothing else to set the title property:

//inside parent component
render(){
 return html`
   <child-component title="${this._privateVariable}"></child-component>
 `
}

This is exactly why you must include _privateVariable in the static properties object of the parent, so that when you set it, the parent component is notified and re-renders, which in turn sets the title property on the child component.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants