Angular React Vue 比较 – 组件篇之生命周期

三大框架中实例化组件并渲染组件视图时,组件实例的生命周期就开始了。生命周期一直伴随着变更检测,框架会检查数据绑定属性何时发生变化,并按需更新视图和组件实例。当从应用中销毁组件实例并从 DOM 中移除它渲染的模板时,生命周期就结束了。

我们的应用可以使用生命周期钩子方法来触发组件生命周期中的关键事件,以初始化新实例,需要时启动变更检测,在变更检测过程中响应更新,并在删除实例之前进行清理。

三大框架关于组件生命周期钩子各不相同,但是对于我们来说最常用到的是挂载、更新和卸载这几个钩子,本章将对这三个钩子来做比较。

Angular 组件生命周期钩子

在这里,我们先列出 Angular 组件生命周期中的钩子,下表中的关于钩子的次序就是组件在生命周期中的执行顺序。

钩子方法 用途 时机
ngOnChanges 当 Angular 设置或重新设置数据绑定的输入属性时响应。该方法接受当前和上一属性值的对象。 如果组件绑定过输入属性,那么在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。
ngOnInit 在 Angular 第一次显示数据绑定和设置组件的输入属性之后,初始化组件。 在第一轮 ngOnChanges() 完成之后调用,只调用一次。而且即使没有调用过 ngOnChanges(),也仍然会调用 ngOnInit()(比如当模板中没有绑定任何输入属性时)。
ngDoCheck 检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。 紧跟在每次执行变更检测时的 ngOnChanges() 和 首次执行变更检测时的 ngOnInit() 后调用。
ngAfterContentInit 当 Angular 把外部内容投影进组件视图或指令所在的视图之后调用。 第一次 ngDoCheck() 之后调用,只调用一次。
ngAfterContentChecked 每当 Angular 检查完被投影到组件中的内容之后调用。 ngAfterContentInit() 和每次 ngDoCheck() 之后调用。
ngAfterViewInit 当 Angular 初始化完组件视图及其子视图调用。 第一次 ngAfterContentChecked() 之后调用,只调用一次。
ngAfterViewChecked 每当 Angular 做完组件视图和子视图或包含该指令的视图的变更检测之后调用。 ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
ngOnDestroy 每当 Angular 每次销毁组件后调用并清扫。在这儿取消订阅可观察对象和事件绑定,以防内存泄漏。 在 Angular 销毁指令或组件后立即调用。

在 Angular 的组件生命周期中并没有称之为挂载、更新和卸载的钩子,为了更方便的在三个框架中做对比,我们把它生命周期中类似于这几个功能的钩子称之为挂载、更新和卸载。

挂载钩子

ngAfterViewInit 钩子会在完全初始化了组件的视图后调用,它只会调用一次。这个钩子中没有参数。

更新钩子

ngOnChanges 钩子会在组件的输入属性发生了变化时调用,它会在组件初始化之前先调用一次。ngOnChanges() 方法获取了一个对象,它把每个发生变化的属性名都映射到了一个 SimpleChange 对象,该对象中有属性的当前值和前一个值。这个钩子会在这些发生了变化的属性上进行迭代,并记录它们。

如果组件并没有绑定任何输入属性,那么此钩子不会被调用。

需要注意的是在 Angular 组件的生命周期中并没有组件自身属性变化后可调用的钩子,如果要监测组件自身属性的变化,可以使用 RxJS 库来创建和订阅可观察的对象。

卸载钩子

ngOnDestroy 钩子会在组件实例被销毁后调用,这个钩子中没有参数。

React 组件生命周期钩子

和其他两个框架不一样,在 React 的函数式组件中并没有可调用的生命周期钩子。想要实现类似挂载、更新和卸载功能的钩子可以使用 useEffect 钩子。

需要注意的是,在编写和读取 Effect 时,要独立地考虑每个 Effect(如何开始和停止同步),而不是从组件的角度思考(如何挂载、更新或卸载)。在本章中是为了与其他两个框架做比较,才从组件的角度来使用 Effect 的。

在这里我们提供一段使用 useEffct 来实现上述三个钩了的示例。

import { useState, useEffect } from 'react';

export default function Clock({ time }) {
  const [index, setIndex] = useState(0);

  useEffect(() => {
    // 【更新钩子】当props与state变更、组件渲染后执行
  });

  useEffect(() => {
    // 【挂载钩子】组件渲染后仅执行一次
    
    return () => {
      // 【卸载钩子】组件在卸载后执行
    }
  }, []);

  useEffect(() => {
    // 【更新钩子】仅在index变更,组件渲染后执行
  }, [index]);

  function handleClick() {
    setIndex(index + 1);
  }

  return (
    <>
      <button onClick={handleClick}>
        Next
      </button>
      <p>{index}</p>
      <div>{time}</div>
    <>
  );
}

挂载钩子

使用 useEffect 钩子,第二个参数传递 [] 时,会在组件渲染后仅调用一次这个钩子。

useEffect(() => {
    // 【挂载钩子】组件渲染后仅执行一次
}, []);

更新钩子

使用 useEffect 钩子,不传递第二个参数时,会在 props 或 state 发生变更、组件渲染后调用这个钩子。

useEffect(() => {
    // 【更新钩子】当props与state变更、组件渲染后执行
});

卸载钩子

在 useEffect 钩子中添加返回的函数会在组件被卸载后执行。

useEffect(() => {
    // 【卸载钩子】组件在卸载后执行
});

Vue组件生命周期钩子

在这里,我们先列出 Vue 组件生命周期中的钩子,下表中的关于钩子的次序就是组件在生命周期中的执行顺序。这些钩子都应该在组件的 setup() 阶段被同步调用。

钩子方法 用途 时机
onBeforeMount 当这个钩子被调用时,组件已经完成了其响应式状态的设置,但还没有创建 DOM 节点。它即将首次执行 DOM 渲染过程。 在组件被挂载之前被调用。
onMounted 这个钩子通常用于执行需要访问组件所渲染的 DOM 树相关的副作用。 在组件挂载完成后执行。
onBeforeUpdate 这个钩子可以用来在 Vue 更新 DOM 之前访问 DOM 状态。在这个钩子中更改状态也是安全的。 在组件即将因为响应式状态变更而更新其 DOM 树之前调用。
onUpdated 这个钩子会在组件的任意 DOM 更新后被调用,这些更新可能是由不同的状态变更导致的,因为多个状态变更可以在同一个渲染周期中批量执行(考虑到性能因素)。 在组件因为响应式状态变更而更新其 DOM 树之后调用。
onBeforeUnmount 当这个钩子被调用时,组件实例依然还保有全部的功能。 在组件实例被卸载之前调用。
onUnmounted 可以在这个钩子中手动清理一些副作用,例如计时器、DOM 事件监听器或者与服务器的连接。 在组件实例被卸载之后调用。

挂载钩子

onMounted 钩子在组件挂载完成后调用,它只会执行一次。

更新钩子

onUpdated 钩子在组件因为响应式状态变更而更新其 DOM 树之后调用。

卸载钩子

onUnmounted 钩子在组件实例被卸载之后调用。

小结

本章介绍了三大框架组件的生命周期中的钩子,对挂载、更新与卸载钩子做了重点说明。

Angular 中是类组件,实例化的组件可以理解成一个类的对象,把组件实例生命周期的钩子当成对象的方法考虑会更好理解。

React 函数组件中并没有可以调用的生命周期钩子,在编写和读取 Effect 时,要独立地考虑每个 Effect(如何开始和停止同步),而不是从组件的角度思考(如何挂载、更新或卸载)。

Vue 组件生命周期中关于挂载、更新和卸载的钩子符合我们的直观描述,更好理解一些。

文章参考链接:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容