Как наблюдать изменения свойств с LitElement

Я не знаю, как наблюдать изменения свойств в LitElement.

Я пробовал эти методы, но я не мог заставить их работать:

  static get properties() {
    return {
      temp1:String,
      temp2: {
       type:String,
       observer: '_temp2Changed'
        }
  };

  temp1Changed(newValue, oldValue){
    console.log("temp1 changed")
  }
  _temp2Changed(newValue, oldValue){
    console.log("temp2 changed")
  }

3 ответа

Решение

Я нашел решение из комплектов PWA от Polymer.

Добавьте следующее к определению вашего элемента:

_propertiesChanged(props, changed, oldProps) {
    console.log("_propertiesChanged(props, changed, oldProps):");
    console.log(props);    
    console.log(changed);  
    console.log(oldProps); 
    if (changed && 'temp1' in changed) {
      console.log("if temp1:"+changed.temp1);
    }
    super._propertiesChanged(props, changed, oldProps); //This is needed here
}

console output:
_propertiesChanged(props, changed, oldProps):
{temp1: "newVal1", temp2: "val2"}
{temp1: "newVal1"}
{temp1: "val1"}
if temp1:newVal1

Версия 0.6.0+

Сначала вы должны указать свойства элемента. Вы можете сделать это, создав статический геттер, который возвращает объект, включающий их имена в качестве ключей и их атрибутную конфигурацию.

updated Метод жизненного цикла будет вызван, когда измененные свойства вызвали повторную визуализацию. Первый аргумент будет возвращать значения до обновления.

class MyComponent extends LitElement {
  static get properties() {
    return {
      foo: {}
    };
  }

  constructor() {
    super();
    this.foo = 0;
    setInterval(() => this.foo++, 1000);
  }

  updated(changedProperties) {
    console.log(changedProperties); // logs previous values
    console.log(this.foo); // logs current value
  }

  render() {
    return html`${this.foo}`;
  }
}

customElements.define("my-component", MyComponent);

Параметр свойства hasChanged:

Вы можете определить эту опцию hasChanged в объявлении свойства в геттере статических свойств. Так же, как и с опцией "тип".

hasChanged должен вернуть true, чтобы обновить элемент.

myProp: { hasChanged(newVal, oldVal) {
 // compare newVal and oldVal
 // return `true` if an update should proceed
}}

Проверить это здесь

Метод жизненного цикла: обновлено

Существует метод жизненного цикла с именем "обновленный", который запускается каждый раз при изменении любого свойства.

Этот метод получает в качестве параметров "changedProperties" с их предыдущими значениями, чтобы вы могли сравнить их с текущими значениями, а затем решить, что вы хотите с ними делать.

Ознакомьтесь с "обновленной" документацией здесь.

Я лично переопределяю метод requestUpdate, чтобы быть в курсе изменений перед рендерингом.

Мой вариант использования - перехватить изменение атрибута "label" для запуска асинхронного запроса данных.

Фрагмент ниже (в TypeScript):

@customElement('my-element')
export default class MyElement extends LitElement {

    @property({type: String})
    label: string | null = null;

    @property({attribute: false})
    private isLoading: boolean = false;

    @property({attribute: false, noAccessor: true})
    private data: MyData | null = null;

    protected render() {/*some code*/}

    requestUpdate(name?: PropertyKey, oldValue?: unknown) {
        if(name && name == "label" && this.label !== oldValue) {
            this.isLoading = true;
            requestData(this.label, this._callbackData);
        }
        return super.requestUpdate(name, oldValue);
    }

    private _callbackData(data: MyData}) {
        this.data = data;
        this.isLoading = false;
    }

}

Таким образом, мой элемент отображается только дважды: один с новой меткой и загрузкой как true, а другой - когда данные доступны.

LitElement автоматически перерисовывает каждый раз, когда изменяется свойство, если это свойство определено в вашем методе _render.

Это отмечено в readme LitElement:

Реакция на изменения: LitElement реагирует на изменения свойств и атрибутов путем> асинхронного рендеринга, гарантируя пакетирование изменений. Это снижает накладные расходы и> поддерживает согласованное состояние.

Например:

_render({firstName, lastName}) {
return html`
  <div> Hello ${firstName} ${lastName} </div>
`;

Будет перерисовываться каждый раз при изменении свойств firstName и lastName. Я надеюсь, что это обеспечивает немного ясности.

Реализуйте метод shouldUpdate(). Источник здесь.

Управляет продолжением обновления. Воплощать в жизнь shouldUpdateчтобы указать, какие изменения свойств должны вызывать обновления. По умолчанию этот метод всегда возвращает true.

function shouldUpdate(changedProperties: Map<any, any>) {
    changedProperties.forEach((oldValue, propName) => {
        const newValue = JSON.stringify(this[propName]);
        console.log(`${propName} changed. oldValue: ${oldValue} newValue: ${newValue}`);
    });
    return true;
}
Другие вопросы по тегам