packages/lit-dev-content/site/tutorials/content/wc-to-lit/12.md
Lit introduces a set of render lifecycle callback methods on top of the native web component callbacks. These callbacks are triggered when declared Lit reactive properties are changed.
{% aside "info" %}
To learn more about the Lit reactive update cycle, see the Lit Lifecycle documentation.
{% endaside %}
To use this feature, you must statically declare which properties are Reactive Properties – properties that will trigger the render lifecycle when changed:
{% switchable-sample %}
import {customElement, property} from 'lit/decorators.js';
export class RatingElement extends LitElement {
...
@property({type: Number})
rating = 0;
@property({type: String, reflect: true})
vote: 'up'|'down'|null = null;
// remove observedAttributes() and attributeChangedCallback()
// remove set rating() get rating()
// remove set vote() get vote()
// remove the _rating and _vote private class members
...
export class RatingElement extends LitElement {
...
static properties = {
rating: {type: Number},
vote: {type: String, reflect: true},
};
constructor() {
super();
this.rating = 0;
this.vote = null;
}
// remove observedAttributes() and attributeChangedCallback()
// remove set rating() get rating()
// remove set vote() get vote()
// remove the _rating and _vote private class members
...
{% endswitchable-sample %}
Here, you:
rating and vote are reactive properties.
LitElement rendering lifecycle when changed.string attributes into properties.{% aside "positive" %}
Pass complex objects as properties.
It is generally good practice to pass complex objects as properties rather than attributes. Read more on reactive property attribute conversion in the Lit documentation.
{% endaside %}
Additionally, the reflect flag on the vote property will automatically update the host element's vote attribute that you formerly updated in the vote setter. It is necessary to reflect the vote attribute so the :host([vote=up]) styles can be applied.
Now update the rating when the vote property changes in the willUpdate() Lit lifecycle method:
{% switchable-sample %}
// import PropertyValues
import {LitElement, html, css, PropertyValues} from 'lit';
...
willUpdate(changedProps: PropertyValues<this>) {
if (changedProps.has('vote')) {
const newValue = this.vote;
const oldValue = changedProps.get('vote');
if (newValue === 'up') {
if (oldValue === 'down') {
this.rating += 2;
} else {
this.rating += 1;
}
} else if (newValue === 'down') {
if (oldValue === 'up') {
this.rating -= 2;
} else {
this.rating -= 1;
}
}
}
}
willUpdate(changedProps) {
if (changedProps.has('vote')) {
const newValue = this.vote;
const oldValue = changedProps.get('vote');
if (newValue === 'up') {
if (oldValue === 'down') {
this.rating += 2;
} else {
this.rating += 1;
}
} else if (newValue === 'down') {
if (oldValue === 'up') {
this.rating -= 2;
} else {
this.rating -= 1;
}
}
}
}
{% endswitchable-sample %}
The logic here is the same from the vote setter logic just moved to to the willUpdate() lifecycle method.
The willUpdate() method is called before render() every time a reactive property is changed. Because LitElement batches property changes and makes rendering asynchronous, changes to reactive properties (like this.rating) in willUpdate() will not trigger unnecessary render lifecycle calls.
Congratulations, you should have a working Lit Element!