LWC的生命周期函数

Posted by Peter Dong on April 6, 2022

LWC的生命周期负责创建, 插入组件到DOM中, 并将其渲染和从DOM中删除. 它还监控已渲染的组件的任何属性变化, Lifecycle钩子其实是一种回调方法, 在组件实例的生命周期的特定阶段被触发. 下面为大家介绍LWC的几个生命周期Hooks.

1. Constructor()

当一个组件的实例被创建时, constructor()被调用. 在这个阶段, 我们不能访问组件的公共属性(@api 修饰), 因为它们还不存在, 如果我们在组件中包含了一个子组件, 那么我们也不能访问子组件的元素, 因为LWC的生命周期流程是从父组件到子组件. 也就是说, 子组件将在父组件被渲染后被渲染.下面的例子显示了我们如何在LWC文件中使用constructor函数.

1
2
3
4
5
6
7
import { LightningElement } from "lwc";

export default class ParentChildDemo extends LightningElement {
  constructor() {
    super(); // calling constructor of LightningElement
  }
}

作为一个必要的步骤,我们需要从构造函数()中调用super()关键字.因为每个LWC组件都扩展了LightningElement,而LightningElement有它的构造函数,我们不应该绕过调用父类的构造函数.

我们可以从构造函数中设置值,但最好的做法是使用getter和setter方法来获取或设置变量的值.请参考下面的例子来更好地理解它.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { api, LightningElement } from "lwc";

export default class ParentChildDemo extends LightningElement {
  variable1;
  variable2;

  constructor() {
    super();
    this.variable1 = "value";
  }

  @api
  get item() {
    return this.variable2;
  }

  set item(value) {
    this.variable2 = value.toUpperCase();
  }
}

对于构造函数,有一些注意事项.

DO’s

  • 设置属性的值, 也可以定义变量.
  • 可以调用 Apex Method
  • 可以调用UI APIs, 比如 uiRecordApi

DON’T

  • 不要试图访问元素的属性,因为它们还不存在.
  • 不能从构造函数中create和dispatch custom events, 比如show toast message

2. ConnectedCallback()

当组件被插入到DOM中时, 它被调用. 当这个方法被执行的时候, 所有的公共属性都已经从它们的父组件那里得到了值. 在这个方法中, 我们可以调用需要将公共属性作为参数的Apex方法, 因为现在公共属性已经存在了.

如果我们想在组件被加载到DOM后执行任何种类的逻辑,我们可以使用connectedCallback()生命周期方法.

1
2
3
4
5
6
7
8
9
10
11
12
13
import { LightningElement, api } from "lwc";

export default class ParentChildDemo extends LightningElement {
  @api publicProperty;

  constructor() {
    super();
  }

  connectedCallback() {
    console.log("Now We can access public property: " + this.publicProperty);
  }
}

要检查组件是否连接到DOM,我们可以使用isConnected属性,如果组件连接了,则返回真,否则返回假.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { LightningElement } from "lwc";

export default class ParentChildDemo extends LightningElement {
  constructor() {
    super();
    let elmt = this.template;
    console.log("From constructor: " + elmt.isConnected); // output: false
  }

  connectedCallback() {
    let elmt = this.template;
    console.log("From connectedCallback: " + elmt.isConnected); // output: true
  }
}

对于connectedCallback函数,有一些注意事项.

DO’s

  • 可以触发一个Custom Event.
  • 可以调用 UI APIs & navigation service
  • 订阅/取消订阅一个message channel
  • 可以访问组件的元素

DON’T

  • 还不能访问任何子组件的元素, 因为这时候子组件还不存在.

3. renderedCallback()

renderedCallback是LWC特有的,其他的都是HTML custom elements规范.由于这个钩子在组件的每次渲染后都会被调用,所以应该对它进行保护,以避免触发无限的渲染循环.当一个属性的值发生变化时,一个组件会被rendered.

下面的示例展示了renderedCallback是如何工作的

我们现在有两个组件: parentLwc 和 childLwc.

parentLwc.html

1
2
3
<template>
  <c-child-lwc></c-child-lwc>
</template>

parentLwc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import { LightningElement } from "lwc";

export default class ParentLwc extends LightningElement {
  constructor() {
    super();
  }

  connectedCallback() {}

  renderedCallback() {
    console.log("renderedCallback() Called From Parent component.");
  }
}

childLwc.html

1
2
3
<template>
  <h1>I'm child component</h1>
</template>

childLwc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import { LightningElement } from "lwc";

export default class ChildLwc extends LightningElement {
  constructor() {
    super();
  }

  connectedCallback() {}

  renderedCallback() {
    console.log("renderedCallback() Called From Child component.");
  }
}

Output logs:

1
2
// renderedCallback() Called From Child component.
// renderedCallback() Called From Parent component.

renderedCallback()方法被多次调用, 导致页面的无用渲染, 为了确保renderedCallback()只在需要的时候被调用, 我们可以使用私有布尔属性来判断.

DO’s

  • 在一个组件完成渲染阶段后执行业务逻辑.
  • 访问组件元素
  • 调用 Apex, UI APIs, navigation service
  • 创建 和 Dispatch custom events

DON’T

  • 不要使用renderedCallback()来改变一个正在设置属性值的组件的状态,可以使用getter和setter.
  • 不能在renderedCallback()中更新一个wire adapter配置的对象的属性,因为这会导致无限循环.
  • 不要在renderedCallback()中更新一个reactive属性或字段,因为这可能会导致无限循环。

4. disconnectedCallback

当一个组件被从DOM中移除时,它就会被执行。它是编写组件被销毁或从DOM中移除后需要实现的逻辑的最佳位置。

1
2
3
4
5
6
7
8
9
10
11
import { LightningElement } from "lwc";

export default class ParentChildDemo extends LightningElement {
  constructor() {
    super();
  }

  disconnectedCallback() {
    console.error("disconnectedCallback() Called From Parent component.");
  }
}

DO’s

  • 移除缓存
  • 移除事件监听器
  • 取消订阅LMS channels

5. errorCallback(error, stack)

在生命周期阶段,当所有子组件出现故障或错误时,它将被执行。它是LWC独有的,其余的都来自HTML规范。通过这个钩子,我们可以给我们的组件设置一个错误边界。 它可以帮助我们记录堆栈信息,并在子组件中遇到错误时渲染一个替代模板。这样,用户就可以知道到底发生了什么,接下来该怎么做。

它类似于javaScript的catch{}块,用于在子组件生命周期钩子中抛出错误的组件。是的,错误边界组件只抓取来自子组件生命周期钩子的错误,而不是来自它自己。

它需要两个参数:error和stack。error是一个javaScript本地错误对象,stack是一个字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { LightningElement } from "lwc";

export default class ParentChildDemo extends LightningElement {
  error;
  stack;

  constructor() {
    super();
  }

  errorCallback(error, stack) {
    console.error("errorCallback() Called From Parent component.")
    this.error = error;
    this.stack = stack;
  }
}

Buy Me a Coffee