lit

Lit Lifecycle Hook - shouldUpdate not working with other loops


I tried using shouldUpdate lifecycle hooks along with other lifecycle hooks. But seems like its not working.

Lit component code

   import { LitElement, css, html } from 'lit';
    import { classMap } from 'lit/directives/class-map.js';
    import { styleMap } from 'lit/directives/style-map.js';

export class MyElement extends LitElement {
  static properties = {
    classes: {},
    styles: {},
    count: { type: Number },
  };
  static styles = css`
    .someclass { border: 1px solid red; padding: 4px; }
    .anotherclass { background-color: navy; }
  `;

  constructor() {
    super();
    this.classes = { someclass: true, anotherclass: true };
    this.styles = { color: 'lightgreen', fontFamily: 'Roboto' };
    this.count = 0;
    console.log('constructor');
  }

  firstUpdated() {
    console.log('first updated');
  }

  toggleCSS() {
    this.classes = {
      ...this.classes,
      anotherclass: !this.classes.anotherclass,
    };
    this.count++;
  }

  changeStyle() {
    this.styles = { ...this.styles, color: 'red' };
  }

  shouldUpdate(changedProperties) {
    changedProperties.forEach((oldValue, propName) => {
      console.log(
        `${propName} changed. oldValue: ${oldValue}, new value ${this[propName]}`
      );
    });
    return true;
  }

  requestUpdate() {
    super.requestUpdate();
    console.log('request update', this.classes);
  }

  willUpdate() {
    console.log('will update');
  }

  performUpdate() {
    super.performUpdate();
    console.log('perform update');
  }

  updated() {
    console.log('updated', this.classes);
  }

  updateComplete() {
    console.log('update complete');
  }

  render() {
    return html`
      <div>
      <div class=${classMap(this.classes)} style=${styleMap(this.styles)}>
      Some content
      </div>
      <button @click=${this.toggleCSS}>Change css </button>
      <button @click=${this.changeStyle}>Change Style </button>
      </div>
    `;
  }
}

window.customElements.define('my-element', MyElement);

Stackblitz For This code

I tried shouldUpdate hook with other lifecycle hooks but it's not working. As per docs, should update use Should update Docs

shouldUpdate(changedProperties: Map<string, any>) {
  // Only update element if prop1 changed.
  return changedProperties.has('prop1'); 
}

Could anyone correct me what's wrong with the code?


Solution

  • You are overriding requestUpdate() without passing through any of the arguments. Request update takes the changed property name and the previous value and possibly other args for internal use which are needed for tracking changed properties.

    You can see the changed properties map will be populated if you fix the override code like this

      requestUpdate(...args) {
        super.requestUpdate(...args);
        console.log('request update', this.classes);
      }
    

    but really there normally isn't a good reason to override requestUpdate() at all, so removing that also will result in the correct behavior.

    As a side note, you also have code that is overriding updateComplete which is not a lifecycle method but is meant to be an internally created promise to that resolves when a reactive update cycle has been completed. You generally would not want to override that either.