React与Vue组件生命周期以及钩子函数

本文详细介绍了React和Vue框架中组件的生命周期,包括挂载、更新和卸载阶段的关键钩子函数及其调用顺序。React的新版生命周期有所调整,移除了不安全的函数,并引入了新的生命周期方法。Vue2和Vue3的生命周期也进行了对比,强调了它们之间的相似性和差异性,如Vue3中新增的setup()函数。此外,文章还提到了错误处理和组件优化策略。
摘要由CSDN通过智能技术生成

组件生命周期

组件生命周期:组件从被创建到挂载到页面中运行,再到组件不用时卸载的过程。

  • 钩子函数,使开发者的代码可以在固定阶段执行。

  • 注意:只有类组件才有生命周期。函数组件每次都是重新运行函数,旧的组件即刻被销毁。

React组件的生命周期

在这里插入图片描述

组件的生命周期主要包括三阶段

  1. 挂载阶段
  2. 更新阶段
  3. 卸载阶段
  • 挂载阶段:组件被创建,执行初始化,并被挂载到DOM中,完成组件的第一次渲染(已经插入真实DOM

  • 更新阶段:组件被挂载到DOM之后,propsstate都可以引起组件的更新(重新渲染

  • 卸载阶段:在组件被卸载前调用(已经移出真实DOM

挂载阶段

  1. constructor()

    • ES6class的构造方法,组件被创建时会首先调用组件的构造方法

    • 初始化state,以及为事件处理程序绑定this

  2. componentWillMount() 不建议使用,已经废用了,是在组件被挂载在DOM之前调用,而且只会被调用一次

  3. render()

    • 根据组件的propsstate返回一个React元素

    • 渲染UI

    • 注意:在render()里面不能调用setState()

    • 实际上是调用React.creatElement()

  4. componentDidMount()

    • 在组件被挂载在DOM之后调用,而且只会被调用一次。

    • 可以调用 setState()

    • 向服务器端发送网络请求,以及处理依赖DOM节点的操作

更新阶段

  1. 父组件调用render方法
  2. 组件调用this.setState
  1. componentWillReceiveProps()

    • 已废用
    • props引起的组件更新过程中被调用
    • state引起的组件更新并不会触发该方法的执行
  2. shouldComponentUpdate()

    • 用于决定组件是否继续执行更新过程,默认值为true

    • 可以用来减少组件不必要的渲染,从而优化组件的性能

    • 对比前后两个propsstate是否相同

  3. componentWillUpdate()

    • 组件初始化时不调用

    • 只有在组件将要更新时才调用,此时可以修改state

  4. render()

    • 根据组件的propsstate返回一个React元素

    • 渲染UI

    • 注意:在render()里面不能调用setState()

    • 实际上是调用React.creatElement()

  5. componentDidUpdate()

    • 组件更新之后被调用

卸载阶段

  1. componentWillUnmount()

    • 在组件被卸载前调用

其他

  • componentDidCatch(error, errorInfo)在子组件发生错误是被调用。

    • 接收errorerrorInfo两个参数,
      • error 表示抛出的错误
      • errorInfo 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息

React 生命周期函数调用顺序

简记,容易记住的生命周期方法

单个组件生命周期函数调用顺序
  1. 单组件初始化

    • constructor -> componentWillMount -> render -> componentDidMount

    • 常用 constructor -> render -> componentDidMount

  2. 单组件更新state

    • shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
  3. 单组件卸载

    • componentWillUnmount
父子组件生命周期函数调用顺序
  1. 父子组件初始化

    • 父组件constructor -> 父组件componentWillMount -> 父组件render -> 子组件constructor -> 子组件componentWillMount -> 子组件render -> 子组件componentDidMount -> 父组件componentDidMount
  2. 父组件更新state

    • 父组件shouldComponentUpdate -> 父组件componentWillUpdate -> 父组件render -> 子组件componentWillReceiveProps -> 子组件shouldComponentUpdate -> 子组件componentWillUpdate -> 子组件render -> 子组件componentDidUpdate -> 父组件componentDidUpdate
  3. 子组件更新state

    • 子组件shouldComponentUpdate -> 子组件componentWillUpdate -> 子组件render -> 子组件componentDidUpdate
  4. 父子组件卸载

    • 父组件componentWillUnmount -> 子组件componentWillUnmount

React组件的生命周期(新版)

在这里插入图片描述

新版本主要是React 16.3+

新版本的react生命周期函数主要变化

  1. 去除了三个不安全函数 componentWillMountcomponentWillReceivePropscomponentWillUpdate
  2. 新增了三个生命周期函数 static getDerivedStateFromPropsgetSnapshotBeforeUpdatestatic getDerivedStateFromError
  • 版本说明

    • componentWillMountcomponentWillReceivePropscomponentWillUpdate 表示使用这些生命周期的代码,有可能在未来的 React 版本中存在缺陷,可能会影响未来的异步渲染。

    • React 16.3 版本:为不安全的生命周期引入别名 UNSAFE_componentWillMount,UNSAFE_componentWillReceiveProps 和 UNSAFE_componentWillUpdate。(旧的生命周期名称和新的别名都可以在此版本中使用)

    • React 16.3 之后的版本:为 componentWillMount,componentWillReceiveProps 和 componentWillUpdate 启用弃用警告。(旧的生命周期名称和新的别名都可以在此版本中使用,但旧名称会记录DEV模式警告)

    • React 17.0 版本:推出新的渲染方式—异步渲染( Async Rendering),提出一种可被打断的生命周期(实际 dom 挂载之前的虚拟 dom 构建阶段),去掉的三个生命周期 componentWillMount,componentWillReceiveProps 和 componentWillUpdate。(从这个版本开始,只有新的“UNSAFE_”生命周期名称将起作用)

挂载阶段

constructor -> getDerivedStateFromProps -> render -> componentDidMount

  1. componentWillMount 不再使用
  2. getDerivedStateFromProps 替换 componentWillMount
  • static getDerivedStateFromProps(props, state) 在组件初始化和组件更新时都会被调用

    • 接收stateprops两个参数

      • 可以通过返回一个对象来更新组件自身的state
      • 返回null来表示接收到的props没有变化,不需要更新 state
    • 静态方法,所以该生命周期钩子函数内部没有this

    • 将父组件传递过来的props映射到子组件的state

    • 注意:子组件通过 setState 更新自身状态时,不会改变父组件的 props

更新阶段

getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate

  1. 新增 getDerivedStateFromProps
  2. 替换 componentWillUpdate 为 getSnapshotBeforeUpdate
  • getSnapshotBeforeUpdate(prevProps, prevState) 在组件更新时被调用。被调用于 render之后、更新 DOM 和 refs 之前。

    • 必须有返回值,返回值将作为 componentDidUpdate 函数方法的第三个参数。

    • 通过this.propsthis.state是最新的数据,函数的参数prevPropsprevState是更新前的数据。可以通过比较,做逻辑处理。

卸载阶段

componentWillUnmount
无变化

其他

  • static getDerivedStateFromError(error) 在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state。

    • 在渲染DOM之前调用,当我们遇到子组件出错的时候可以渲染备用UI,常用作错误边界。

    • componentDidCatch是在DOM渲染完后才会调用,可以用来输出错误信息或上传一些错误报告。

React 生命周期函数调用顺序

单组件
  1. 单组件初始化

    • constructor -> getDerivedStateFromProps -> render -> componentDidMount
  2. 单组件更新state

    • getDerivedStateFromProps -> shouldComponentUpdate -> render -> getSnapshotBeforeUpdate -> componentDidUpdate
  3. 单组件卸载

    • componentWillUnmount
父子组件
  1. 父子组件初始化

    • 父组件constructor -> 父组件getDerivedStateFromProps -> 父组件render -> 子组件constructor -> 子组件getDerivedStateFromProps -> 子组件render -> 子组件componentDidMount -> 父组件componentDidMount
  2. 父组件更新state

    • 父组件getDerivedStateFromProps -> 父组件shouldComponentUpdate -> 父组件render -> 子组件getDerivedStateFromProps -> 子组件shouldComponentUpdate -> 子组件render -> 子组件getSnapshotBeforeUpdate -> 父组件getSnapshotBeforeUpdate -> 子组件componentDidUpdate -> 父组件componentDidUpdate
  3. 子组件更新state

    • 子组件getDerivedStateFromProps -> 子组件shouldComponentUpdate -> 子组件render -> 子组件getSnapshotBeforeUpdate -> 子组件componentDidUpdate
  4. 父子组件卸载

    • 父组件componentWillUnmount -> 子组件componentWillUnmount

VUE@2组件的生命周期

在这里插入图片描述

组件的生命周期

  1. 初始化阶段
  2. 编译阶段
  3. 挂载阶段
  4. 更新阶段
  5. 销毁阶段

初始化阶段

  • beforeCreate

    • 在实例初始化之后,进行数据侦听和事件/侦听器的配置之前同步调用。

    • 实例的datamethods等配置还未初始化,无法调用,只能使用一些默认事件

  • created

    • 在实例创建完成后被立即同步调用。

    • 实例已完成对选项的处理,意味着以下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数。

    • 挂载阶段还没开始,且 $el.property 目前尚不可用。

    • 模板还没有编译,不能获取到DOM。

编译阶段

  • VUE对象是否指定el

  • VUE对象是否指定template

  • <template>编译到render函数中

挂载阶段

  • beforeMounted

    • 挂载开始之前被调用,相关的 render 函数首次被调用。

    • 函数在模板渲染之前调用,也就是DOM节点挂载到真实DOM树之前调用。

    • 此模板进行编译,会调用render函数生成虚拟DOM,同样无法获取DOM节点(此时只存在虚拟DOM,还在JS级别)。

  • mounted

    • 实例被挂载后调用,这时 el 被新创建的 vm.$el 替换。

    • 注意:mounted不会保证所有的子组件也都被挂载完成。

      • 如果你希望等到整个视图都渲染完毕再执行某些操作,可以在 mounted 内部使用 vm.$nextTick
    • 执行该钩子函数时,模板编译完成,而且挂载到真实DOM树上面去了,也就是页面可以显示了。(该钩子在服务器端渲染期间不被调用)

生命周期组件调用顺序

单组件
  1. 单组件初始化

    • beforeCreate -> created -> beforeMount -> mounted
  2. 单组件更新

    • beforeUpdate -> updated
  3. 单组件卸载

    • beforeDestroy -> destroyed
父子组件
  1. 父子组件初始化

    • 父组件beforeCreate -> 父组件created -> 父组件beforeMount -> 子组件beforeCreate -> 子组件created -> 子组件beforeMount -> 子组件mounted -> 父组件mounted
  2. 父组件更新data,此data没传递给子组件

    • 父组件beforeUpdate -> 父组件updated
  3. 父组件更新data,此data传递给了子组件

    • 父组件beforeUpdate -> 子组件beforeUpdate -> 子组件updated -> 父组件updated
  4. 子组件更新data

    • 子组件beforeUpdate -> 子组件updated
  5. 父子组件卸载

    • 父组件beforeDestroy -> 子组件beforeDestroy -> 子组件destroyed -> 父组件destroyed

更新阶段

  • beforeUpdate

    • 在数据发生改变后,DOM 被更新之前被调用。

    • 这里适合在现有 DOM 将要被更新之前访问它,比如移除手动添加的事件监听器。

    • 该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务器端进行。

    • 该钩子函数在data数据发生变化之后调用,data里面的数据已经是最新的了,但是页面上DOM还没有更新最新的数据

  • updated

    • 在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用。

    • 当这个钩子被调用时,组件 DOM 已经更新,可以执行依赖于 DOM 的操作。要相应状态改变,通常最好使用计算属性或 watcher 取而代之。

    • 注意,updated 不会保证所有的子组件也都被重新渲染完毕。如果你希望等到整个视图都渲染完毕,可以在 updated 里使用 vm.$nextTick

    • 该钩子函数会在data数据更新之后执行,而且此时页面也渲染更新完成了,显示的就是最新的数据。

    • 注意:不要在updated中修改data数据,很容易造成死循环。

销毁阶段

  • beforeDestroy

    • 实例销毁之前调用。实例仍然完全可用。

    • 在这个钩子函数里面解除一些全局或者自定义事件。

  • destroyed

    • 实例销毁后调用。

    • 该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VUE@2生命周期</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
</head>
<body>
<div id="app">
    {{ message }}
</div>
<div class="test">
    {{ msg }}
</div>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        }
    });
</script>
<script type="text/javascript">
    const myVue = new Vue({
        el: ".test",
        data: {
            msg: "在控制台输入 myVue.msg=666666,可以改变值触发更新前,更新后"
        },
        beforeCreate: function () {
            console.log("建立前 --- beforeCreate");
        },
        created: function () {
            // 在实例创建之后同步调用。数据绑定,计算属性,方法,watcher/事件回调。
            // 没有开始 DOM 编译,$el 还不存在,但是实例存在,即 this.a 存在,可打印出来 。
            console.log("建立 --- created");
        },
        beforeMount: function () {
            console.log("渲染前 --- beforeMount");
        },
        mounted: function () {
            console.log("渲染后 --- mounted");
        },
        beforeUpdate: function () {
            console.log("更新前 --- beforeUpdate");
        },
        updated: function () {
            console.log("更新后 --- updated");
        },
        beforeDestroy: function () {
            // 触发方式,在console里面打myVue.$destroy();
            // 在开始销毁实例时调用。此时实例仍然有功能。
            console.log("销毁前 --- beforeDestroy");
        },
        destroyed: function () {
            // 触发方式,在console里面打myVue.$destroy(); 其中myVue.$destroy(true)是删除DOM节点,会触发detached函数,但是实例仍然存在
            // 在实例被销毁之后调用。此时所有的绑定和实例的指令已经解绑,注意是解绑不是销毁,所有的子实例也已经被销毁。
            console.log("已销毁 --- destroyed");
        }
    });
</script>
</body>

其他钩子函数

  • errorCaptured

    • 在捕获一个来自后代组件的错误时被调用。

    • 钩子函数的三个参数:错误对象、发生错误的组件实例、一个包含错误来源信息的字符串。

    • 该钩子函数可以返回 false 以阻止该错误继续向上传播。

  • activated

    • 被 keep-alive 缓存的组件激活时调用。
  • deactivated

    • 被 keep-alive 缓存的组件失活时调用。

VUE@3组件的生命周期

在这里插入图片描述

  1. setup() : 开始创建组件之前,在 beforeCreate 和 created 之前执行,创建的是 data 和 method

  2. onBeforeMount() : 组件挂载到节点上之前执行的函数;

  3. onMounted(): 组件挂载完成后执行的函数;

  4. onBeforeUpdate(): 组件更新之前执行的函数;

  5. onUpdated(): 组件更新完成之后执行的函数;

  6. onBeforeUnmount(): 组件卸载之前执行的函数;

  7. onUnmounted(): 组件卸载完成后执行的函数;

  8. onActivated(): 被包含在<keep-alive>中的组件,会多出两个生命周期钩子函数,被激活时执行;

  9. onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行;

  10. onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数。

生命周期执行顺序

生命周期函数的运行基本顺序是 setup -> beforeCreate -> created

单个组件
  1. 单组件初始化

    • setup -> created -> onBeforeMount -> onRenderTracked -> onMounted
  2. 单组件更新

    • onRenderTriggered-> onBeforeUpdate -> onUpdated
  3. 单组件卸载

    • onBeforeDestroy -> onDestroyed
父子组件
  1. 父子组件初始化

    • 父组件setup -> 父组件onBeforeMount -> 父组件onRenderTracked -> 子组件setup -> 子组件onBeforeMount -> 子组件onRenderTracked -> 子组件onMounted -> 父组件onMounted
  2. 父组件更新data,此data没传递给子组件

    • 父组件onRenderTriggered-> 父组件onBeforeUpdate ->父组件 onUpdated
  3. 父组件更新data,此data传递给了子组件

    • 父组件onRenderTriggered -> 父组件onBeforeUpdate -> 子组件onBeforeUpdate -> 子组件onUpdated -> 子组件onUpdated
  4. 子组件更新data

    • 子组件onRenderTriggered -> 子组件onBeforeUpdate -> 子组件onUpdated
  5. 父子组件卸载

    • 父组件onBeforeDestroy -> 子组件onBeforeDestroy -> 子组件onDestroyed -> 父组件onDestroyed

VUE@2VUE@3对比

vue@2vue@3
beforeCreatesetup(()=>{})
createdsetup(()=>{})
beforeMountonBeforeMount(()=>{})
mountedonMounted(()=>{})
beforeUpdateonBeforeUpdate(()=>{})
updatedonUpdated(()=>{})
beforeDestroyonBeforeUnmount(()=>{})
destroyedonUnmounted(()=>{})
activatedonActivated(()=>{})
deactivatedonDeactivated(()=>{})
errorCapturedonErrorCaptured(()=>{})
  • Vue@2Vue@3钩子变化不大,使用setup()钩子来替代 beforeCreate、created 两个钩子函数。

在这里插入图片描述

VUEReact生命周期对比

对比的目的在于处理相同与不同

相同点

  1. VueReact 生命周期函数基本类似,组件的创建、更新、卸载都有对应的函数方法调用。

  2. 单组件、父子组件渲染类似。

不同点

  • 参数比较:

    • Vue生命周期函数除了 errorCaptured 都是没有参数的。
    • React生命周期函数都有参数并且能访问到旧的或新的props和state。
  • 组件更新

    • React父组件更新,子组件一定都会更新渲染,除非自己手动优化(继承PureComponent或者实现shouldComponent方法)。
    • Vue中除非子组件依赖父组件的数据改变了,否则子组件是不会重新渲染的。
  • 组件更新处理

    • Vue 数据改变就一定会重新渲染,无法阻止。
    • React 能通过 shouldComponent 方法来决定是否需要渲染。
  • 错误处理

    • Vue 在组件报错的时候页面还是会渲染,只是引发出错的地方可能数值不对。
    • React 组件报错的时候会导致页面空白,编译报错将提示信息到浏览器(getDerivedStateFromError 做边界处理)。
  • 生命周期影响

    • React的生命周期函数,大多都在处理当前的propsstate
    • VUE相比较多了缓存的生命周期函数 activated、deactivated 和用于开发调试的renderTracked、renderTriggered生命周期函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值