【react从入门到精通】深入理解React生命周期

news2025/1/11 2:17:02

文章目录

  • 前言
  • React技能树
  • React的生命周期是什么
  • React v16.0前的生命周期
    • 组件初始化(initialization)阶段
    • 组件挂载(Mounting)阶段
    • 组件更新(update)阶段
    • 组件销毁阶段
  • React v16.4 的生命周期
  • 总结
  • 写在最后

在这里插入图片描述

前言

在上一篇文章《react入门这一篇就够了》中我们已经掌握了React的基本知识。通过使用React组件我们对页面进行渲染;通过使用React事件处理函数对用户操作进行响应;通过React状态的改变对页面进行刷新。本文中我们将深入的了解React的生命周期,以及在这些生命周期可以做些什么。

React技能树

React 技能树
├── JSX
│   ├── 语法
│   ├── 元素渲染
│   ├── 组件
│   ├── Props
│   ├── State
│   └── 生命周期
├── 组件通信
│   ├── 父子组件通信
│   ├── 兄弟组件通信
│   ├── 跨级组件通信
│   ├── Context
│   └── Redux
├── 样式
│   ├── 内联样式
│   ├── CSS Modules
│   └── Styled Components
├── 路由
│   ├── React Router
│   ├── 动态路由
│   └── 嵌套路由
├── 数据请求
│   ├── Axios
│   ├── Fetch
│   └── GraphQL
├── 状态管理
│   ├── Redux
│   ├── MobX
│   └── Recoil
├── 常用库和框架
│   ├── Ant Design
│   ├── Material UI
│   ├── Bootstrap
│   ├── Semantic UI
│   └── Tailwind CSS
├── 测试
│   ├── Jest
│   ├── Enzyme
│   └── React Testing Library
├── 构建工具
│   ├── Webpack
│   └── Parcel
└── 服务端渲染
    ├── Next.js
    └── Gatsby

React的生命周期是什么

React的生命周期表示了React组件从构建到注销所经历的一系列过程。React生命周期有各自执行的顺序和作用。主要包括的生命周期为:组件的初始化阶段,组件的挂载阶段,组件的更新阶段以及组件的销毁阶段。

React v16.0前的生命周期

有些团队不一定会升到16版本,所以16前的生命周期还是很有必要掌握的。

组件初始化(initialization)阶段

也就是以下代码中类的构造方法( constructor() ),Test类继承了react Component这个基类,也就继承这个react的基类,才能有render(),生命周期等方法可以使用,这也说明为什么函数组件不能使用这些方法的原因。

super(props)用来调用基类的构造方法( constructor() ), 也将父组件的props注入给子组件,供子组件读取(组件中props只读不可变,state可变)。

而constructor()用来做一些组件的初始化工作,如定义this.state的初始内容。

import React, { Component } from 'react';

class Test extends Component {
  constructor(props) {
    super(props);
  }
}

组件挂载(Mounting)阶段

此阶段分为componentWillMount,render,componentDidMount三个时期。

componentWillMount:
在组件挂载到DOM前调用,且只会被调用一次,在这边调用this.setState不会引起组件重新渲染,也可以把写在这边的内容提前到constructor()中,所以项目中很少用。

render:
根据组件的props和state(无论两者的重传递和重赋值,无论值是否有变化,都可以引起组件重新render) ,return 一个React元素(描述组件,即UI),不负责组件实际渲染工作,之后由React自身根据此元素去渲染出页面DOM。render是纯函数(Pure function:函数的返回结果只依赖于它的参数;函数执行过程里面没有副作用),不能在里面执行this.setState,会有改变组件状态的副作用。

componentDidMount:
组件挂载到DOM后调用,且只会被调用一次

简言之,componentWillMount函数在我们Render方法前触发属于渲染前,在这个函数之中我们可以异步向服务器端请求Render函数渲染需要使用的数据。Render函数是我们熟练掌握的渲染方法,在其中构建我们组件的UI。componentDidMount是在我们Render函数执行之后也就是已经渲染了我们DOM树之后触发,在这个函数中我们可以针对页面渲染完成之后希望进行处理的一系列动作。

组件更新(update)阶段

在讲述此阶段前需要先明确下react组件更新机制。setState引起的state更新或父组件重新render引起的props更新,更新后的state和props相对之前无论是否有变化,都将引起子组件的重新render。

造成组件更新有两类(三种)情况:

1.父组件重新render
父组件重新render引起子组件重新render的情况有两种

a. 直接使用,每当父组件重新render导致的重传props,子组件将直接跟着重新渲染,无论props是否有变化。可通过shouldComponentUpdate方法优化。

class Child extends Component {
   shouldComponentUpdate(nextProps){ // 应该使用这个方法,否则无论props是否有变化都将会导致组件跟着重新渲染
        if(nextProps.someThings === this.props.someThings){
          return false
        }
    }
    render() {
        return <div>{this.props.someThings}</div>
    }
}

b.在componentWillReceiveProps方法中,将props转换成自己的state

class Child extends Component {
    constructor(props) {
        super(props);
        this.state = {
            someThings: props.someThings
        };
    }
    componentWillReceiveProps(nextProps) { // 父组件重传props时就会调用这个方法
        this.setState({someThings: nextProps.someThings});
    }
    render() {
        return <div>{this.state.someThings}</div>
    }
}

根据官网的描述

在该函数(componentWillReceiveProps)中调用 this.setState() 将不会引起第二次渲染。

是因为componentWillReceiveProps中判断props是否变化了,若变化了,this.setState将引起state变化,从而引起render,此时就没必要再做第二次因重传props引起的render了,不然重复做一样的渲染了。

2.组件本身调用setState,无论state有没有变化。可通过shouldComponentUpdate方法优化。

class Child extends Component {
   constructor(props) {
        super(props);
        this.state = {
          someThings:1
        }
   }
   shouldComponentUpdate(nextStates){ // 应该使用这个方法,否则无论state是否有变化都将会导致组件重新渲染
        if(nextStates.someThings === this.state.someThings){
          return false
        }
    }

   handleClick = () => { // 虽然调用了setState ,但state并无变化
        const preSomeThings = this.state.someThings
         this.setState({
            someThings: preSomeThings
         })
   }

    render() {
        return <div onClick = {this.handleClick}>{this.state.someThings}</div>
    }
}

此阶段分为componentWillReceiveProps,shouldComponentUpdate,componentWillUpdate,render,componentDidUpdate

componentWillReceiveProps(nextProps)
此方法只调用于props引起的组件更新过程中,参数nextProps是父组件传给当前组件的新props。但父组件render方法的调用不能保证重传给当前组件的props是有变化的,所以在此方法中根据nextProps和this.props来查明重传的props是否改变,以及如果改变了要执行啥,比如根据新的props调用this.setState触发当前组件的重新render

shouldComponentUpdate(nextProps, nextState)
此方法通过比较nextProps,nextState及当前组件的this.props,this.state,返回true时当前组件将继续执行更新过程,返回false则当前组件更新停止,以此可用来减少组件的不必要渲染,优化组件性能

ps:这边也可以看出,就算componentWillReceiveProps()中执行了this.setState,更新了state,但在render前(如shouldComponentUpdate,componentWillUpdate),this.state依然指向更新前的state,不然nextState及当前组件的this.state的对比就一直是true了。

componentWillUpdate(nextProps, nextState)
此方法在调用render方法前执行,在这边可执行一些组件更新发生前的工作,一般较少用。

render
render方法在上文讲过。

componentDidUpdate(prevProps, prevState)
此方法在组件更新后被调用,可以操作组件更新的DOM,prevProps和prevState这两个参数指的是组件更新前的props和state

简言之,组件props或者state状态发生变化是所触发,通过对属性以及状态值进行监听可以得知他们发生了改变从而触发我们的render函数对相应的组件进行重新渲染。完成这一系列动作就达到了React组件自动更新的效果。

组件销毁阶段

此阶段只有一个生命周期方法:componentWillUnmount

componentWillUnmount
此方法在组件被卸载前调用,可以在这里执行一些清理工作,比如清楚组件中使用的定时器,清楚componentDidMount中手动创建的DOM元素等,以避免引起内存泄漏。

在这个生命周期中我们要确认对需要释放资源的部分进行释放。养成一个良好的编码习惯是很重要的。

React v16.4 的生命周期

变更缘由

原来(React v16.0前)的生命周期在React v16推出的Fiber之后就不合适了,因为如果要开启async rendering,在render函数之前的所有函数,都有可能被执行多次。

原来(React v16.0前)的生命周期有哪些是在render前执行的呢?

componentWillMount
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate

如果开发者开了async rendering,而且又在以上这些render前执行的生命周期方法做AJAX请求的话,那AJAX将被无谓地多次调用。。。明显不是我们期望的结果。而且在componentWillMount里发起AJAX,不管多快得到结果也赶不上首次render,而且componentWillMount在服务器端渲染也会被调用到(当然,也许这是预期的结果),这样的IO操作放在componentDidMount里更合适。

禁止不能用比劝导开发者不要这样用的效果更好,所以除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代。

也就是用一个静态函数getDerivedStateFromProps来取代被deprecate的几个生命周期函数,就是强制开发者在render之前只做无副作用的操作,而且能做的操作局限在根据props和state决定新的state

React v16.0刚推出的时候,是增加了一个componentDidCatch生命周期函数,这只是一个增量式修改,完全不影响原有生命周期函数;但是,到了React v16.3,大改动来了,引入了两个新的生命周期函数。

新引入了两个新的生命周期函数:getDerivedStateFromProps,getSnapshotBeforeUpdate

getDerivedStateFromProps
getDerivedStateFromProps本来(React v16.3中)是只在创建和更新(由父组件引发部分),也就是不是不由父组件引发,那么getDerivedStateFromProps也不会被调用,如自身setState引发或者forceUpdate引发。

React v16.3
这样的话理解起来有点乱,在React v16.4中改正了这一点,让getDerivedStateFromProps无论是Mounting还是Updating,也无论是因为什么引起的Updating,全部都会被调用,具体可看React v16.4 的生命周期图。

React v16.4后的getDerivedStateFromProps

static getDerivedStateFromProps(props, state) 在组件创建时和更新时的render方法之前调用,它应该返回一个对象来更新状态,或者返回null来不更新任何内容。

getSnapshotBeforeUpdate
getSnapshotBeforeUpdate() 被调用于render之后,可以读取但无法使用DOM的时候。它使您的组件可以在可能更改之前从DOM捕获一些信息(例如滚动位置)。此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

官网给的例子:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    //我们是否要添加新的 items 到列表?
    // 捕捉滚动位置,以便我们可以稍后调整滚动.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    //如果我们有snapshot值, 我们已经添加了 新的items.
    // 调整滚动以至于这些新的items 不会将旧items推出视图。
    // (这边的snapshot是 getSnapshotBeforeUpdate方法的返回值)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

总结

在本文中我们了解了React的生命周期,深入分析了React每个生命周期的意义。了解了利用生命周期中的函数能够帮助我们实现什么样的功能以及为什么要这么做。有了以上的只是基础我们对React的理解又更近一步。更够写出更加健壮完善的代码。

React v16.0前的生命周期与React v16.4 的生命周期不同点总结:

1、react16支持async rendering

2、react16.4 新引入了两个新的生命周期函数:getDerivedStateFromProps,getSnapshotBeforeUpdate

3、除了shouldComponentUpdate,其他在render函数之前的所有函数(componentWillMount,componentWillReceiveProps,componentWillUpdate)都被getDerivedStateFromProps替代。

写在最后

✨原创不易,希望各位大佬多多支持。

👍点赞,你的认可是我创作的动力。

⭐️收藏,感谢你对本文的喜欢。

✏️评论,你的反馈是我进步的财富。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/478153.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软件STM32cubeIDE下STM32F1xx和STM32F4xx使用:备份寄存器+复位标志位-基础样例

软件STM32cubeIDE下STM32F1xx和STM32F4xx使用&#xff1a;备份寄存器复位标志位-基础样例 1、前言2 、 实验环境3、自我总结&#xff08;1&#xff09;对于备份寄存器&#xff08;BKP&#xff09;:&#xff08;2&#xff09;对于复位标志位&#xff08;RCC_CSR&#xff09;&…

【5G RRC】RSRP、RSRQ以及SINR含义、计算过程详细介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

一道经典的小学数学题,和它背后的贪心算法(35)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 这个五一小长假&#xff0c;你玩得怎么样&#xff1f; 今天&#xff0c;咱们先做一道经典的小学数学题&#xff0c;…

Enabling Fast and Universal Audio Adversarial Attack Using Generative Model

Enabling Fast and Universal Audio Adversarial Attack Using Generative Model https://www.winlab.rutgers.edu/~yychen/ AAAI 2021 文章目录 Enabling Fast and Universal Audio Adversarial Attack Using Generative ModelAbstractIntroductionLimitations of Prior WorkT…

每日一个小技巧:1招教你怎么将照片无损放大

照片是一种记录、分享和保存记忆的重要方式。它可以记录特殊的时刻和经历&#xff0c;如毕业典礼、婚礼、旅游等&#xff0c;为我们锁住美好回忆。不知道大家有没有经历过&#xff0c;在手机或者电脑上打开一张拍摄的照片&#xff0c;却发现它的尺寸太小了&#xff0c;手动放大…

C语言从入门到精通

文章目录 C语言1.helloworld1.1 pause1.2 cls清屏1.3 加法运算1.4 hello 2 常量变量和数据类型2.1 常量2.2 变量2.3 sizeof数据类型大小2.4 无符号整型2.5 字符类型2.5.1 字符类型简介2.5.2 字符类型运算 2.6 实数型2.7 进制和转换2.8 数据溢出 3. 运算符和分支循环语句3.1 字符…

D. Decorate Apple Tree(记录每个点,叶子节点数目)

Problem - D - Codeforces 在Arkady的花园里有一棵苹果树。它可以表示为连接着枝干的节点集合&#xff0c;以便从任何一个节点到达任何其他节点时只有一种方法。节点从1到n进行编号&#xff0c;节点1称为根。 节点v的子树是指一组节点u&#xff0c;使得从u到根的路径必须经过v…

基于SpringBoot+Vue+Java的社区医院管理服务系统(附源码+数据库)

摘 要 在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括社区医院管理服务系统的网络应用&#xff0c;在外国线上管理系统已经是很普遍的方式&#xff0c;不过国内的管理系统可能还处于起步阶段。社区医院管理服务系统具有社区…

【动态规划】从入门到实践---动态规划详解

目录 1.动态规划概念 一.定义数组元素的含义 二.找到数组元素之间的关系表达式 三.找到初始值 2.案例详解 一&#xff1a;爬楼梯 1.定义数组元素的含义 2.找到数组元素之间的关系表达式 3.找到初始值 案例二&#xff1a;最短路径 题目&#xff1a; 做题步骤&#xf…

【BeautifulSoup下】——05全栈开发——如桃花来

目录索引 CSS选择器&#xff1a;实例演示&#xff1a;*1.根据标签名去找&#xff0c;不用加任何修饰&#xff0c;多个条件用空格隔开&#xff0c;一层一层找&#xff1a;**2.class类名前加. &#xff1a;**3. 多个逐级条件之间用空格隔开&#xff1a;* 除了标签名选择器之外&am…

Unity - Render Doc - 解决 Waiting For Debugger 导致连接不了 APP 的问题

环境 Unity : 2020.3.37f1 Pipeline : BRP RDC : 1.26 问题 平常有一些公司内的游戏发布在移动端运行会有各种异常&#xff0c;但是 unity editor (android opengl es / dx) 下正常 如果没有真机抓帧分析&#xff0c;是搞不定的 然后 RenderDoc 在抓发布出来的调试包也抓不…

extern\const\static的使用详解

1.extern 利用关键字extern&#xff0c;可以在一个文件中引用另一个文件中定义的变量或者函数&#xff0c;extern 可以应用于全局变量、函数或模板声明。 关键字 extern 具有四种含义&#xff0c;具体取决于上下文&#xff1a; 在非 const 全局变量声明中&#xff0c;extern …

理解getTypeParameters的含义

使用java泛型有时会看到getTypeParameters方法&#xff0c;这个方法是什么意思&#xff0c;下面就来具体了解一下&#xff1a; 官方给出的解释如下&#xff1a; Returns an array of TypeVariable objects that represent the type variables declared by the generic declar…

第十九章 Unity 其他 API

本节介绍一些其他经常使用的Unity类。首先&#xff0c;我们回顾一下Vector3向量类&#xff0c;它既可以表示方向&#xff0c;也可以表示大小。它在游戏中可以用来表示角色的位置&#xff0c;物体的移动/旋转&#xff0c;设置两个游戏对象之间的距离。在我们之前的课程中&#x…

【Unity入门】22.动态创建实例

【Unity入门】动态创建实例 大家好&#xff0c;我是Lampard~~ 欢迎来到Unity入门系列博客&#xff0c;所学知识来自B站阿发老师~感谢 &#xff08;一&#xff09;脚本实例化预制体对象 &#xff08;1&#xff09;Instantiate克隆创建对象 昨天我们学习了预制体这个概念&#…

spring 容器结构/机制debug分析--Spring 学习的核心内容和几个重要概念--IOC 的开发模式

目录 Spring Spring 学习的核心内容 解读上图: Spring 几个重要概念 ● 传统的开发模式 解读上图 ● IOC 的开发模式 解读上图 代码示例—入门 xml代码 注意事项和细节 1、说明 2、解释一下类加载路径 3、debug 看看 spring 容器结构/机制 Spring Spring 学习的…

ChatGPT学习研究总结

目录 ChatGPT研究总结 一、程序接入用途不大 二、思考&#xff1a;如何构建一个类似ChatGPT的自定义模型 一些ChatGPT研究学习资料&#xff08;来源网络&#xff09; &#xff08;1&#xff09;一文读懂ChatGPT模型原理 &#xff08;2&#xff09;MATLAB科研图像处理——…

Windows更新【bug】

Windows更新【bug】 前言推荐Windows更新问题解决 最后 前言 以下内容源自【bug】 仅供学习交流使用 推荐 Win11安全更新问题 仍为解决 Windows更新 问题 完成更新以维护设备安全性 你的设备缺少重要的安全更新。请确保设备保持打开状态并接通电源&#xff0c;以便更新可…

评价基于GPT和Bert的方法并用于生信文本识别PPI

检测蛋白质-蛋白质相互作用&#xff08;PPI&#xff09;对于理解遗传机制、疾病发病机制和药物设计至关重要。然而&#xff0c;随着生物医学文献的快速增长&#xff0c;越来越需要自动和准确地提取PPI以促进科学知识发现。预训练语言模型&#xff0c;例如生成式预训练Transform…

学历:门槛还是机会?

目录 一、学历和职业之间的关系认知 二、不同的文化和传统也会对学历带来不同的解读 三、在学习、生活及工作中学历带来的局限性 四、造成“孔乙己长衫”现象的深层次原因 五、给与学弟学妹们一点毕业就业的建议 是否应该追求高学历一直是社会上热议的话题。有人认为学历代…