解构React生命周期机制

剖析React生命周期的运作机制

1、React生命周期

1.1、何为React生命周期?

当我们借助各类框架开展程序开发时,在框架启动、程序初始运行、页面之间相互交互、数据渲染到页面之上以及程序运行结束的整个过程里,存在一个闭环式的操作流程。在这个闭环的起始点与结束点之间的各个节点处,框架为我们提供了特定的函数,我们可以自行调用这些函数来执行相应操作,这便是生命周期。

简单来讲: 组件从创建、更新直至销毁的完整历程。

其意义体现在:有助于深入理解组件的运行模式、实现更为复杂的组件功能、剖析组件出错的缘由等。

注意: 在React中存在函数组件和类组件。类组件拥有生命周期函数,而函数组件则借助useEffect来达成生命周期函数的功能。

1.2、演变历程

生命周期的每一个阶段都会伴随着若干方法的调用,这些方法就是生命周期的钩子函数,它们的作用是为开发者在不同阶段对组件进行操作提供时机。

众多的生命周期钩子,归结起来实则只有三个过程:挂载、更新、卸载,挂载和卸载仅会执行一次,更新则会执行多次。

  • 挂载:已然插入到真实的DOM中
  • 渲染(更新):正在被重新进行渲染
  • 卸载:已然从真实的DOM中移除

一个完整的React组件生命周期会依次调用如下钩子:

https://i-blog.csdnimg.cn/img_convert/20478b2e8ab984eec6e2eec6e3041bf5.png

2、类组件生命周期

2.1、类组件是什么

类组件是运用ES6中的关键字class来进行定义的。类组件具备特定的生命周期方法,能够在不同阶段执行一些操作。类组件中必须实现render()方法来描述组件的界面,并且可以通过state属性来存储和管理组件的内部状态。
例如:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      state1: 'This is a React class.'
    };
  }
  render() {
    return (
      <div>{state1}</div>
    );
  }
}
2.2、旧版生命周期

https://i-blog.csdnimg.cn/img_convert/e4d7a3abb4974bbf42d28f2cacbbc505.png

2.3、废弃与新增

原先(React v16.0之前)的生命周期在React v16推出Fiber之后就不再适配了,因为要是开启async rendering,在render函数之前的所有函数都有可能被执行多次。所以,除了shouldComponentUpdate之外,其他在render函数之前的所有函数(componentWillMount、componentWillReceiveProps、componentWillUpdate)都由getDerivedStateFromProps来替代。

以下生命周期钩子将会逐步被废弃,它们的共同特点是都带有will的钩子:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

引入了以下两个生命周期钩子:

  • getDerivedStateFromProps
  • getSnapshotBeforeUpdate

注意:

getDerivedStateFromProps前面需要加上static保留字,声明为静态方法,不然会被react忽略掉;getDerivedStateFromProps里面的this为undefined。

3、新版类组件生命周期

3.1、React的生命周期包含哪些?
  1. 挂载阶段(Mounting)
  2. 更新阶段(Updating)
  3. 卸载阶段(Unmounting)
  4. 错误处理阶段(Error Handling)

https://i-blog.csdnimg.cn/img_convert/6496630ac16029813d6b454863bb6936.png

3.2、生命周期详细解析

在React中,组件的生命周期历经不同阶段,每个阶段都对应着相应的生命周期方法。以下是针对React 16版本之后的组件生命周期方法进行的详细剖析:

挂载阶段(Mounting):(当组件实例被创建并插入到DOM中时)

  • constructor(props):组件的构造函数,在React组件挂载之前,也就是创建组件的时候被调用,用于初始化状态以及绑定事件处理方法。该方法只会执行一次。
  • static getDerivedStateFromProps(props, state):这是一个静态方法,接收props和state两个参数。第一个参数是即将更新的props,第二个参数是上一个状态的state,可以通过比较props和state来设置一些限制条件,防止无用的state更新。每次接收到新的props之后都会返回一个对象作为新的state,如果返回null则表明不需要更新state。
  • render():准备对组件的UI结构进行渲染。在此处创建虚拟dom、进行diff算法以及更新dom树等操作。
  • componentDidMount():组件第一次渲染完成后,在组件挂载(插入到DOM树中)后立即被调用,通常用于执行一次性的操作,比如数据获取、订阅事件等。

更新阶段(Updating):(当组件的props或state发生变化时会触发更新)

  • static getDerivedStateFromProps(props, state):在组件接收到新的props时被调用,用于根据新的props来更新state。
  • shouldComponentUpdate(nextProps, nextState):在渲染执行之前被调用,首次渲染或者使用forceUpdate()时不会调用该方法。返回true就会更新dom(使用diff算法进行更新),返回false则能阻止更新(不调用render)
  • render():重新对组件的UI结构进行渲染。
  • getSnapshotBeforeUpdate(prevProps, prevState):在最近一次渲染输出(提交到DOM上)之前被调用,此时DOM树还没有改变,我们可以在这里获取DOM改变前的信息,例如更新前DOM的滚动位置。
  • componentDidUpdate(prevProps, prevState, snapshot):第一个参数是上一次props的值,第二个参数是上一次state的值。在更新后立即被调用,首次渲染不会执行此方法。通常用于处理更新后的操作,比如数据同步、DOM操作等。

卸载阶段(Unmounting):(当组件从DOM中移除时)

  • componentWillUnmount():在组件渲染之后、组件卸载及销毁之前直接被调用,只调用一次。在此方法中执行必要的清理操作,例如,清除timer,取消网络请求或者清除在componentDidMount()中创建的订阅等。

错误处理阶段(Error Handling):(当渲染过程、生命周期或者子组件的构造函数中抛出错误时)

  • static getDerivedStateFromError(error):当子组件抛出错误时被调用,用于更新组件的state以渲染降级UI。
  • componentDidCatch(error, info):用于捕获组件内部的JavaScript错误、网络请求失败等异常情况,并进行错误处理。
3.3、实例
3.3.1、挂载阶段
import React ,{Component} from 'react'

class Child extends Component{
  // 初始化
  constructor(props){
    console.log('01构造函数')       
    super(props)
    this.state={}
  }
  // 组件将要挂载时候触发的生命周期函数
  componentWillMount(){
    console.log('02组件将要挂载')
  }
  // 组件挂载完成时候触发的生命周期函数
  componentDidMount(){
    console.log('04组件挂载完成')
  }
  // 组件挂载时触发的生命周期函数
  render(){
    console.log('03数据渲染render')
    return(
      <div>Child组件</div>
    ) 
  }
}
export default Child

// 控制台打印结果顺序如下:
// 01构造函数
// 02组件将要挂载
// 03数据渲染render
// 04组件挂载完成
3.3.2、更新阶段

数据更新时第一步是shouldComponentUpdate来确认是否要更新数据,当这个函数返回true的时候才会进行更新,并且这个函数可以声明两个参数nextProps和nextState,nextProps是父组件传给子组件的值,nextState是数据更新之后的值,这两个值可以在这个函数中获取到。第二步当确认更新数据之后componentWillUpdate将要更新数据,第三步依旧是render,数据发生改变render重新进行了渲染。第四步是componentDidUpdate数据更新完成。

import React, { Component } from 'react'

class Child extends Component {
  constructor(props) {
    super(props)
    this.state = {
      msg: '我是一个msg数据'
    }
  }

  //是否要更新数据,如果返回true才会更新数据
  shouldComponentUpdate(nextProps, nextState) {
    console.log('01是否要更新数据')
    return true;                //返回true,确认更新
  }
  //将要更新数据的时候触发的生命周期函数
  componentWillUpdate() {
    console.log('02组件将要更新')
  }
  //更新完成时触发的生命周期函数
  componentDidUpdate() {
    console.log('04组件更新完成')
  }
  //更新数据方法
  setMsg() {
    this.setState({
      msg: '我是改变后的msg数据'
    })
  }
  render() {
    console.log('03数据渲染render')
    return (
      <div>
        {this.state.msg}
        <button onClick={() => this.setMsg()}>点我更新msg的数据</button>
      </div>
    )
  }
}
export default Child

点击按钮更新数据,控制台打印结果顺序如下:

01是否要更新数据
02组件将要挂载
03数据渲染render
04组件更新完成

3.3.3、总结

这些生命周期方法帮助我们在组件创建、更新和销毁时执行特定的操作,确保应用程序的正常运行和良好的用户体验。

4、函数组件生命周期

只有类组件才有生命周期,函数组件不存在生命周期(类组件需要实例化,而函数组件不需要)。React v16.8.0推出了Hooks API,其中的一个API叫做useEffect可以解决相关问题。Hook基本完全替代了类组件的语法,后续的React项目就完全是函数式组件了。

4.1、函数组件是什么

函数组件是一种以声明式方式定义组件的形式,使用function关键字来定义一个新的函数。函数组件被设计成无状态的,仅仅以props作为输入并返回React元素作为输出。函数组件不需要实现类组件中的生命周期方法和state状态。
例如:

import React, { useState } from 'react'
import TestLifeCycle from './pages/testLifeCycle'

const App = () => {
  const [show, setShow] = useState(true)
  const unMountClick = () => {
    setShow(!show)
  }
  return (
    <div className="App">
      { show ? <TestLifeCycle/> : null }
      <button onClick={unMountClick}>卸载</button>
    </div>
  )
}
export default App
4.2、模拟类组件生命周期钩子

useEffect是一个高阶函数,可以在一个组件中多次使用,相当于componentDidMount(组件挂载完成)、componentDidUpdate(组件更新完成)和componentWillUnmount(组件将要卸载之前)的组合。

useEffect方法可以传递两个参数:

第一个参为函数结构,是必填项;

第二个参数可为数组,是选填项。

所以函数组件可以分为三种:

第一种: 不带参数

useEffect(() => {
  // todo...
})
// 不传第二个参数,则会在 state 的任意一个属性改变时都会触发该函数回调

初始化和组件重新渲染的时候执行。父组件重新渲染也会执行。

第二种: 带空数组 []

useEffect(() => {
  // todo...
}, [])
// 第二个参数为空时只会在第一次渲染时执行

组件初始化(挂载)的时候执行,可以用于ajax数据请求。

第三种: 带具体参数的数组(可以多个参数)

useEffect(() => {
  // todo...
}, [参数1,参数2,...])

其中一个值或多个发生改变时执行。

用useEffect代替生命周期:

1、模拟componentDidMount():

useEffect(() => {}, [])函数组件挂载时执行一次

2、模拟componentDidUpdate():

useEffect(() => {})只要有state变化,就执行函数

useEffect(() => {}, [state1, state2])state1或state2变化,就执行函数

3、模拟componentWillUnmount:

useEffect(() => { 挂载执行的函数体 return () => { 卸载执行的函数体 } })

总结:

https://i-blog.csdnimg.cn/img_convert/cc6cf7662b588cb8038a649ee388c62a.png

例子:

import React, { useState, useRef, useEffect } from 'react'

export default function MyComponent() {
// 第一个参数是函数结构,第二个参数是空数组 ===> 表示ComponentDidMount 组件挂载完成
    useEffect(() => {
        console.log('组件挂载完成了1');
    }, []);
// 一打开页面,组建完成挂载,自动执行


// 第一个是函数结构,不传递第二个参数 ===> 表示表示ComponentDidMount + ComponentDidUpdate
// 即:组件挂载完成以及组件状态更新
    useEffect(() => {
            console.log('组件挂载完成 & 组件更新完成');
        })
    // 组件挂载完成会执行一次,组件每次更新状态值也会执行一次

        let [num, setNum] = useState(100);
        let [isLogin, setisLogin] = useState(true); 

    // 第一个是函数结构,第二个是非空数组,数组中传入state的状态数据 ===> 当这个状态数据被更新时才执行回调函数
    // 【注】数组的参数如果没有任何值的话,空数组,表示什么状态数据都不更新,回调函数不执行
        useEffect(() => {
            console.log('当islogin状态值发生改变时,组件挂载完成&组件更新完成')
        }, [isLogin])       


    // 模拟ComponentwillUnmount
    // 在脚手架中当尝试修改组件之后,react会将组件先卸载,然后再来一个新的重新挂载
    // 通过函数里返回函数的方式
    useEffect(() => {
        console.log('任意属性变了');
        return () => {
            console.log('该组件要销毁了');
        }
    })
    // return 中的内容会在页面卸载时执行,类似生命周期函数 componentWillUnmount。
    // 比如在页面销毁的之前先清除定时器,避免不必要的性能开支。
          useEffect(() => {
            // 清除定时器
            return () => {
                clearInterval(timer1)
            }
        }, [])

注意:

useEffect方法的第一个参数的函数是一个同步函数,不接收async参数,(原因是如果设置了async,返回值就成了promise对象,非一个函数了)。

如果想要在useEffect()方法中添加异步代码,需要在函数中在单独声明一个函数。

useEffect(() => {
     //函数声明
     async function main() {
         let res = await 100;
     }
     //函数调用
     main();
})

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/13675.html

(0)
LomuLomu
上一篇 2025 年 9 月 19 日
下一篇 2025 年 9 月 19 日

相关推荐

  • 2025年最新PyCharm激活码及永久破解教程(支持2099年)

    本方法适用于JetBrains全家桶,包括PyCharm、IDEA、DataGrip、Goland等开发工具! 先展示最新PyCharm版本成功破解的截图,可以看到已经完美激活至2099年! 下面将详细介绍如何将PyCharm永久激活至2099年的完整步骤。 此方法具有以下特点:- 支持Windows、Mac和Linux三大操作系统- 兼容所有历史版本- 成…

    PyCharm激活码 2025 年 8 月 12 日
    9900
  • WebStorm破解过程是否需要关闭杀毒软件?

    免责声明:下文所述 WebStorm 破解补丁、激活码均源自互联网公开渠道,仅供个人学习研究,禁止商业用途。若条件允许,请支持正版!官方正版低至 32 元/年:https://panghu.hicxy.com/shop/?id=18 WebStorm 是 JetBrains 出品的全能前端 IDE,支持 Windows、macOS 及 Linux。下面手把手…

    2025 年 9 月 19 日
    2100
  • 如何破解并永久激活PyCharm,2024版激活码教程

    本教程适用于PyCharm、PyCharm、DataGrip、Goland等,支持Jetbrains全家桶! 废话不多说,先给大家看一下最新PyCharm版本的破解截图,可以看到已经成功破解至2099年,激活效果非常好! 接下来,我会通过图文方式,详细讲解如何激活PyCharm至2099年。 无论你使用的是Windows、Mac还是Linux系统,无论你的P…

    PyCharm破解教程 2025 年 4 月 12 日
    59800
  • 2024 GoLand最新激活码,GoLand永久免费激活码2025-02-05 更新

    GoLand 2024最新激活码 以下是最新的GoLand激活码,更新时间:2025-02-05 🔑 激活码使用说明 1️⃣ 复制下方激活码 2️⃣ 打开 GoLand 软件 3️⃣ 在菜单栏中选择 Help -> Register 4️⃣ 选择 Activation Code 5️⃣ 粘贴激活码,点击 Activate ⚠️ 必看!必看! 🔥 获取最新激活…

    2025 年 2 月 5 日
    52300
  • Redis事务与锁机制在并发秒杀场景的深入剖析

    十. Redis 事务与 “锁机制”——并发秒杀处理的详细阐述 目录 十. Redis 事务与 “锁机制”——并发秒杀处理的详细阐述 1. Redis 事务的定义 2. Redis 事务的三大特性 3. Redis 事务相关指令 Multi、Exec、discard 及 “watch & unwatch” 3.1 快速入门(演示 Redis 事务控制…

    2025 年 6 月 18 日
    15300

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信