【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是改变对象里面的数据,不会触发ngOnchangestest = {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]
参考资料:
  1. Angular:生命周期和钩子函数

  2. Angular 完整组件生命週期介绍

  3. NG0100: Expression has changed after it was checked

  4. https://www.angularthink.in/2023/05/lifecycle-hooks.html

  5. 组件的生命周期

  6. angular单项数据流

  7. Complete Guide: Angular lifecycle hooks

posted @ 2023-08-06 23:19  unuliha  阅读(214)  评论(0)    收藏  举报