【Angular】angular组件的生命周期钩子函数有什么用?

上图[4]展示了angular生命周期钩子函数的执行顺序,在此之前,angular会先执行constructor
函数。
一、基本说明
1. constructor
-
用途:初始化组件,设定属性,注入依赖。
-
说明1:构造函数中能读取到本组件内部定义的基本变量和函数的值,但是读不到
@ContentChildren
、@ContentChild
、@ViewChildren
、@ViewChild
、@Input
等带修饰符的外部传入的或从模板中取的值,但是可以拿到它们的默认值,如@Input a = 12
中的a
,此时其值保存为12
。 -
说明2:通常只在其中注入依赖,不要放入任何特定于组件的页面相关的任务。这是因为构造函数是在
ngOnInit
之前调用的,此时组件还没有被创建,只有组件类被实例化。 -
说明3:类的构造函数保证其所有字段(也称为类成员)都设置为默认值。
2. ngOnChanges
-
用途:
@Input()
属性发生变化时调用。参数changes:SimpleChange
中记录了变化的变量值的当前值、上一个值、是否是第一次变化3个字段的信息。 -
说明1:如果 @Input 是个对象,对象里面的数据改变但是引用没有变化是不会触发这个函数。[1]如
test.a = 12
是改变对象里面的数据,不会触发ngOnchanges
,test = {a:12}
是重新赋值,引用地址发生变化,会触发ngOnchanges
。 -
说明2:此处才能访问到
@Input
外部传入的变量值。 -
说明3:如果组件/指令没有
@Input
值,或者没有从外部传入@Input
定义的变量,不会触发该函数。
3. ngOnInit
- 用途:初始化组件状态,通常用于初始化数据和API调用、初始化
formGroup
、设置监听或订阅subscribe
。[4] [6] - 说明1:可以用于所有的初始化/声明,因为此时组件将被初始化。
- 说明2:父组件先于子组件执行该初始化函数,这样可以方便子组件使用父组件的资源。
4. ngDoCheck
-
用途:用户可以自定义变化(click handlers, http requests, route changes…)检测逻辑,用户可以在Angular 无法或不愿意自己检测的变化时增加反应逻辑。
-
说明:成本非常高,因为调用次数特别频繁,比如点击input,或者input失焦时均会触发,建议仅在Debug时使用。
5. ngAfterContentInit
-
用途:用于与组件的投影内容进行交互。
-
说明1:在组件的生命周期中,在第一个 ngDoCheck 之后,只调用此方法一次。
-
说明2:此处Angular 已经将外部内容投影到组件的视图,此处才能访问到
@ContentChildren
、@ContentChild
的 ElementRef。 -
说明3:此时组件的
template
还没初始化。
6. ngAfterContentChecked
- 说明1:在组件的生命周期中,在 ngAfterContentInit 之后和随后的每次 ngDoCheck 之后调用此方法一次。
- 说明2:在 Angular 已经检查了当前
digest loop
中投影到组件中的内容之后调用。[7] - 说明3:因为每次
doCheck
之后都会调用,就算没有声明@ContentChild
变量也会调用,尽量不要使用。
7. ngAfterViewInit
-
用途:当需要在组件视图加载完成后,修改视图内容或操作DOM节点、或者与子组件进行交互时,可在其中执行相关任务。例如,在页面加载完成后修改其标题、更新页面元素样式、给页面元素添加监听等。
-
说明1:在组件的生命周期中,在 ngAfterContentChecked 之后,只调用此方法一次。
-
说明2:此处才能访问到
@ViewChildren
、@ViewChild
的ElementRef。同时,每次执行本钩子函数之前,都会先将子组件的周期钩子执行到ngAfterViewChecked
之后,才会继续执行后面周期函数。 -
说明3:在此处 Angular 已经组合了组件的视图和它的子视图,可以访问到组件的
template
。

8. ngAfterViewChecked
-
用途:在组件视图或子组件的视图发生变化后,如某个指标值发生变化后,可以根据新的值添加对应的操作。但调用频率很高,尽量不要使用。
-
说明1:此方法在 ngAfterViewInit 之后调用一次,然后在每次后续的 ngAfterContentChecked 之后调用一次。
-
说明2:在 Angular 已经在当前
digest loop
中检查了组件的视图及其子视图之后调用。 -
说明3:因为每次
doCheck
之后都会调用,就算没有声明@ViewChild
变量也会调用,尽量不要使用。
9. ngOnDestroy
- 用途: 用于在组件销毁时清理资源。主要为了避免内存泄漏,如从可观察对象中取消订阅或释放资源、分离事件处理程序、结束计时器、
二、Q&A
1. 为什么会遇到ExpressionChangedAfterItHasBeenCheckedError报错?
- 原因:组件html上展示的数据和ts代码里的数据不一致。即组件在完成变更检测之后,某个数据又被子组件/孙组件的代码更新了。这在angular中是不被允许的,因为angular是执行的单向数据流,即一旦 component 中的变化检测已经完成了,任何在 child component 或者更低层级的 component 都不允许去改变 component 中的属性。
- 解决方案:找到数据不同步的原因,正确使用钩子函数(推荐);强制手动检测(setTimeout、Promise、cd.detectChanges)(最后的手段)[3]。