第12节——生命周期

一、概念

生命周期指 React 组件从装载至卸载的全过程,这个过程内置多个函数供开发者在组件的不同阶段执行需要的逻辑。

状态组件主要通过 3 个生命周期阶段来管理,分别是 挂载阶段(MOUNTING),更新阶段(UPDATING)和卸载阶段(UNMOUNT)。

从纵向划分,可以划分为 Render 阶段和 Commit 阶段

Render 阶段:纯净且不包含副作用,可能会被 React 暂停、中止或重新启动

Commit 阶段:可以使用 DOM,运行副作用,安排更新

img

二、挂载阶段触发生命周期

1、constructor

构造函数(这个并不是react的生命周期)

语法

class A extends React.Component {/**** @param {*} props 继承 React.Component 的属性方法,它是不可变的 read-only* @param {*} context 全局上下文。* @param {*} updater 包含一些更新方法的对象* 比如this.setState 最终调用的是 this.updater.enqueueSetState*/constructor(props, context, updater) {super(props) }
}

触发时机

在组件初始化的时候触发一次。

使用场景

1、设置初始化状态

因为组件的生命周期中任何函数都可能要访问 State,那么整个周期中第一个被调用的构造函数便是初始化 state 最理想的地方;

2、绑定成员函数上下文引用

因为在 ES6 语法下,类的每个成员函数在执行时的 this 并不是和类实例自动绑定的;

而在构造函数中 this 就是当前组件实例,所以,为了方便将来调用,可以将这个实例的特定函数绑定 this 为当前类实例;

建议定义函数方法时直接使用箭头函数,就无须在构造函数中进行函数的 bind 操作。

2、static getDerivedStateFromProps

语法

  /**** @param {*} nextProps 当前的props* @param {*} prevState 修改前的state* 该生命周期函数必须有返回值,* 它需要返回一个对象来更新 State,*/static getDerivedStateFromProps(nextProps, prevState) {if (nextProps.num) {return {...prevState,num: nextProps.num * 2}}return prevState;}

触发时机

该函数会在组件化实例化后和重新渲染前调用(生成 VirtualDOM 之后,实际 DOM 挂载之前),意味着无论是父组件的更新、props 的变化或通过 setState 更新组件内部的 State,它都会被调用。

注意

在组件装载和更新阶段都会触发。

如果父组件导致了组件的重新渲染,即使属性没有更新,这一方法也会被触发;

如果你只想处理 props 的前后变化,你需要将上一个 props 值存到 state 里作为镜像;

该生命周期函数是一个静态函数,所以函数体内无法访问指向当前组件实例的指针 this;

使用场景

该生命周期函数被设计成静态方法的目的是为了保持该方法的纯粹。通过根据父组件输入的 props 按需更新 state,这种 state 叫做衍生 state,返回的对象就是要增量更新的 state,除此之外不应该在里面执行任何操作。

通过设计成静态方法,能够起到限制开发者无法访问 this 也就是实例的作用,这样就不能在里面调用实例方法或者 setState 以破坏该生命周期函数的功能。

这个生命周期函数也经历了一些波折,原本它是被设计成 初始化、父组件更新 和 接收到 Props 才会触发,现在只要渲染就会触发,也就是 初始化 和 更新阶段 都会触发

import React from "react";export default class LearnLife extends React.Component {state = {num: 1,};/**** @param {*} nextProps 当前的props* @param {*} prevState 修改前的state* 该生命周期函数必须有返回值,* 它需要返回一个对象来更新 State,* 或者返回 null 表达不更新*/static getDerivedStateFromProps(nextProps, prevState) {if (nextProps.num) {return {...prevState,num: nextProps.num * 2}}return nextProps;}render() {return (<div><div>父组件2倍的num -- {this.state.num}</div><div>父组件传过来的值 -- {this.props.num}</div></div>);}
}

3、UNSAFE_componentWillMount(componentWillMount)

此生命周期函数将在 React v17 正式废弃。

触发时机

在构造函数和装载组件(将 DOM 树渲染到浏览器中)之间触发。装载组件后将执行 render 渲染函数。因此在此生命周期函数里使用 setState 同步设置组件内部状态 state 将不会触发重新渲染。

注意

避免在该方法中引入任何的副作用(Effects)或订阅(Subscription)。对于这些使用场景,建议提前到构造函数中

4、render

渲染函数(这个并不是react的生命周期)

概念

它是一个仅仅用于渲染的纯函数,返回值完全取决于 state 和 props,不能在函数中任何修改 state、props、请求数据等具有副作用的操作,不能读写 DOM 信息,也不能和浏览器进行交互(例如 setTimeout)。如果需要和浏览器交互,在 componentDidMount() 中或者其它生命周期方法完成相关事务。

此渲染函数并不做实际的渲染动作(渲染到 DOM 树),它返回的只是一个 JSX 的描述对象(及组件实例),何时进行真正的渲染是有 React 库决定的。而 React 肯定是要把所有组件返回的结果综合起来,才能知道如何产生真实的 DOM 树。也就是说,只有 React 库调用所有组件的渲染函数之后,才有可能完成 DOM 装载,这时候才会依次调用 componentDidMount 函数作为装载的收尾。

注意

请勿在此函数中使用 setState 方法;

请勿在此函数中修改 props、state 以及数据请求等具有副作用的操作

5、componentDidMount

语法

class Life extends React.component {componentDidMount () {}
}

触发时机

组件完全挂载到网页上后触发。

使用场景

发送网络请求;任何依赖于 DOM 的初始化操作;添加事件监听;如果使用了 Redux 之类的数据管理工具,也能触发 action 处理数据变化逻辑

为什么在这个生命周期里面发送网络请求

之所以在 componentDidMount 中而不是在构造函数中进行数据请求的原因在于:如果数据加载完毕后,即 state 已经有值了,但是组件还没有渲染出来,会报错。但是这里有一些把数据拉取提前到 constructor 函数的思路:在 contructor 函数中,通过 Promise 来进行数据的请求,并且绑定到当前实例对象上,然后在 componentDidMount 中执行 Promise 把数据更新到 state 上

三、更新阶段触发的生命周期

1、UNSAFE_componentWillReceiveProps(componentWillReceiveProps)

此生命周期函数将在 React v17 正式废弃。推荐使用 static getDerivedStateFromProps() 代替

语法

/*nextProps 当前的props*/
componentWillReceiveProps(nextProps) {}

触发时机

当父组件的渲染函数被调用,在渲染函数中被渲染的子组件就会经历更新阶段,不管父组件传给子组件的 props 有没有改变,都会触发该生命周期函数。当组件内部调用 setState 更新内部状态 state 时触发更新阶段不会触发该函数

2、shouldComponentUpdate

语法

在一个更新生命周期中,组件及其子组件将根据该方法返回的布尔值来决定是否继续这次更新过程(重新渲染)。这样你可以在必要的时候阻止组件的渲染生命周期(Render Lifecycle)方法,避免不必要的渲染

 /*** * @param {*} nextProps 当前的props* @param {*} nextState 当前的state* @returns 根据逻辑判断返回 true 表示继续进行组件渲染,否则将停止组件渲染过程。默认返回 true,也就是说,只要组件触发了更新,组件就一定会更新*/shouldComponentUpdate (nextProps, nextState) {return true}

触发时机

每次组件因为 state 和 props 变化而更新时,在重新渲染前该生命周期函数都会触发,让 React 知道当前 state 或 props 的改变是否影响组件的输出(渲染)。

使用场景

如果性能是个瓶颈,尤其是有几十个甚至上百个组件的时候,使用 shouldComponentUpdate 可以优化渲染效率,提升应用的性能;

使用 React.PureComponent 组件基类能自动实现一个 shouldComponentUpdate 生命周期钩子,可以默认为组件更新校验,但是只会对更新数据进行浅层对照;

通常用于条件渲染,优化渲染的性能

例子

实现点击按钮num+1 当num为偶数据的时候视图不渲染

import React from "react";export default class ShouldComponentUpdate extends React.Component {state = {num: 1,};/**** @param {*} nextProps 当前的props* @param {*} nextState 当前的state* @returns return false 不渲染 true 渲染*/shouldComponentUpdate(nextProps, nextState) {/*** 偶数的时候不渲染*/return nextState.num % 2 !== 0;}add() {this.setState({num: this.state.num + 1,});}render() {return (<div><div>{this.state.num}</div><button onClick={() => this.add()}>+1</button></div>);}
}

3、UNSAFE_componentWillUpdate(componentWillUpdate)

此生命周期函数将在 React v17 正式废弃。建议使用componentWillRreceiveProps代替

触发时机

这个方法是一个更新生命周期中重新渲染执行之前的最后一个方法。你已经拥有了下一个属性和状态,他们可以在这个方法中任由你处置。你可以利用这个方法在渲染之前进行最后的准备

注意

此钩子函数在初始化渲染的时候不会被触发;

请勿在此函数中使用 setState 方法,会导致循环调用。

4、render

渲染函数。与上文所提及的 render 生命周期函数一致,用于输出 JSX 并经过 React 处理后渲染至浏览器

5、getSnapshotBeforeUpdate

语法

  /*** * @param {*} prevProps 更新前的props* @param {*} prevState 更新前的state* @returns 返回值可以在componentDidUpdate中接收*/getSnapshotBeforeUpdate (prevProps, prevState) {return null}

触发时机

该生命周期函数会在组件即将挂载时触发,它的触发在 render 渲染函数之后。由此可见,render 函数并没有完成挂载操作,而是进行构建抽象 UI(也就是 Virtual DOM)的工作。该生命周期函数执行完毕后就会立即触发 componentDidUpdate 生命周期钩子。

使用场景

该生命周期函数能让你捕获某些从 DOM 中才能获取的(可能会变更的)信息(例如,元素重新渲染后页面各种定位位置的变更等)。比如网页滚动位置,不需要它持久化,只需要在组件更新以后能够恢复原来的位置即可

注意

该生命周期函数返回的值将作为第三个参数传递给 componentDidUpdate,我们可以利用这个通道保存一些不需要持久化的状态,用完即可舍弃。

(这个生命周期不是经常需要的,但可以用于在恢复期间手动保存滚动位置的情况。)

该函数的出现是为了 React 17 的异步渲染而准备的

6、componentDidUpdate

语法

  /*** * @param {*} prevProps 更新前的props* @param {*} prevState 更新前的state* @param {*} snapshot getSnapshotBeforeUpdate传过来的*/componentDidUpdate (prevProps, prevState, snapshot) {}

触发时机

组件每次重新渲染后触发,相当于首次渲染(初始化)之后触发 componentDidMount

注意

在该生命周期中使用 setState 时,必须加 if 条件判断,通过判断 prevProps、prevState 和 this.state 之间的数据变化,来判断是否执行相关的 state 变更逻辑,这使得尽管在 componentDidUpdate 中调用了 setState 进行再更新,但是直至条件不成立,就不会造成程序死循环。

此生命周期函数不会在初始化渲染的时候触发

总结

相比装载阶段的生命周期函数,更新阶段的生命周期函数使用的相对来说要少一些。常用的是 getDerivedStateFromProps、shouldComponentUpdate,前者经常用于根据新 props 的数据去设置组件的 State,而后者则是常用于优化,避免不必要的渲染

四、卸载阶段

1、componentWillUnmount

语法

componentWillUnmount () {}

触发时机

在组件卸载和销毁之前触发。可以利用这个生命周期方法去执行任何清理任务

使用场景

用于注销事件监听器;取消网络请求;取消定时器;解绑 DOM 事件。

注意

在该方法中调用 setState 不会触发 render,因为所有的更新队列,更新状态都被重置为 null

五、为什么react17后删除了那些生命周期

react 打算在17版本推出新的 Async Rendering,提出一种可被打断的生命周期,而可以被打断的阶段正是实际 dom 挂载之前的虚拟 dom 构建阶段,也就是要被去掉的三个生命周期。本身这三个生命周期所表达的含义是没有问题的,但 react 官方认为我们(开发者)也许在这三个函数中编写了有副作用的代码,所以要替换掉这三个生命周期,因为这三个生命周期可能在一次 render 中被反复调用多次

六、捕获错误(一般了解)

1、static getDerivedStateFromError

语法

import React from "react";export default class GetDerivedStateFromError extends React.Component {/*** * @param {*} error 错误信息* @returns * 它接收抛出的错误作为参数并且需要返回值用于更新 State*/static getDerivedStateFromError(error) {return }render () {return (<div><div>1</div></div>)}
}

触发时机

该生命周期函数会在子孙组件抛出错误时执行

使用场景+注意点

该生命周期函数中可用于修改 state 以显示错误提醒的 UI,或者将错误信息发送到服务端进行 Log 用于后期分析;

在捕获到错误的瞬间,React 会在这次渲染周期中将这个组件渲染为 null,这就有可能导致他的父组件设置他上面的 ref 获得 null 而导致一些问题

和componentDidCatch相比

这个生命周期函数与 getDerivedStateFromProps 类似,唯一的区别是他只有在出现错误的时候才触发,他相对于 componentDidCatch 的优势是在当前的渲染周期中就可以修改 State,以在当前渲染就可以出现错误的 UI,而不需要一个 null 的中间态。

而这个方法的出现,也意味着以后出现错误的时候,修改 state 应该放在这里去做,而后续收集错误信息之类的放到 componentDidCatch 里面

例子

import React from "react";
import AComponent from './a'export default class ErrorComponent extends React.Component {state = {isShowError: false}/*** * @param {*} error 错误信息* @returns * 它接收抛出的错误作为参数并且需要返回值用于更新 State*/static getDerivedStateFromError(error) {console.log(error)return {isShowError: true}}render () {if (this.state.isShowError) {return (<div>组件内部发生错误</div>)}return (<div><div>1</div>{/* 当前组件会触发一个错误 */}<AComponent></AComponent></div>)}
}

2、componentDidCatch

语法

componentDidCatch () {}

触发时机

该生命周期函数会在子孙组件抛出错误时触发。

相关使用和 getDerivedStateFromError 几乎一致

3、错误边界(Error Boundary)

是 React 组件,并不是损坏的组件树。错误边界捕捉发生在子组件树中任意地方的 JavaScript 错误,打印错误日志,并且显示回退的用户界面。错误边界捕捉渲染期间、在生命周期方法中和在它们之下整棵树的构造函数中的错误。

可以定制一个只有 componentDidCatch 生命周期函数的 ErrorBoundary 组件。当捕获错误,则显示错误提示,如果没有捕获到错误,则显示子组件。

将需要捕获错误的组件作为 ErrorBoundary 的子组件渲染,一旦子组件抛出错误,整个应用依然不会崩溃,而是被 ErrorBoundary 捕获

import React, { Component } from 'react';class ErrorBoundary extends Component {state = { hasError: false };render() {if (this.state.hasError) {return <h1>发生错误.</h1>;}return this.props.children;}componentDidCatch(error, info) {this.setState({ hasError: true });}
}export default ErrorBoundary;
定制一个只有 componentDidCatch 生命周期函数的 ErrorBoundary 组件。当捕获错误,则显示错误提示,如果没有捕获到错误,则显示子组件。将需要捕获错误的组件作为 ErrorBoundary 的子组件渲染,一旦子组件抛出错误,整个应用依然不会崩溃,而是被 ErrorBoundary 捕获```jsx
import React, { Component } from 'react';class ErrorBoundary extends Component {state = { hasError: false };render() {if (this.state.hasError) {return <h1>发生错误.</h1>;}return this.props.children;}componentDidCatch(error, info) {this.setState({ hasError: true });}
}export default ErrorBoundary;

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TIA博途从V15.1版本升级到V16后,下载配方时出错,动作异常终止

TIA博途从V15.1版本升级到V16后,下载配方时出错,动作异常终止 1. 读取配方的时候没有问题,完全正常,没有任何错误提示。 2. 但是在下载的时候,就提示了“出错。动作异常终止” 根据以往的经验分析,有可能是配方变量里面没有相对应的地址时候下载会出错,但是配方画面相对…

Windows NUMA编程实践 – 处理器组、组亲和性、处理器亲和性及版本变化

Windows在设计之初没有考虑过对大数量的多CPU和NUMA架构的设备的支持&#xff0c;大部分关于CPU的设计按照64个为上限来设计。核心数越来越多的多核处理器的进入市场使得微软不得不做较大的改动来进行支持&#xff0c;因此Windows 的进程、线程和NUMA API在各个版本中行为不一样…

基于Java+SpringBoot+Vue前后端分离大学生智能消费记账系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

国产10米分辨率的卫星介绍、下载和处理教程

10米分辨率的资源卫星介绍、下载和处理教程 简介 说起免费的10米分辨率卫星影像,大家首先想到的是sentinel卫星。但其实还有我国的中巴地球资源卫星04星(CBERS04)。 中巴地球资源卫星(China Brazil Earth Resources Satellite, CBERS)是中国和巴西共同投资、联合研制的地球…

PCIe DL_Feature详解

DL_Feature的引入 Data Link Control and Management State Machine在PCIe Gen4引入了DL_Feature这个状态&#xff0c;该状态主要用来协商PCIe link 两端是否支持新的DL Feature&#xff0c;目前为止DL Feature只引入了Scaled Flow Control 来提高Gen4及以上的效率。   DL_Fe…

qt信号与槽

输入账户密码成功则跳转界面 widget.cpp #include "widget.h" //自己的头文件Widget::Widget(QWidget *parent) //构造函数的定义: QWidget(parent) …

自建音乐服务器Navidrome之一

这里写自定义目录标题 1.1 官方网站 2. Navidrome 简介2.1 简介2.2 特性 3. 准备工作4. 视频教程5. 界面演示5.1 初始化页5.2 专辑页 前言 之前给大家介绍过 Koel 音频流服务&#xff0c;就是为了解决大家的这个问题&#xff1a;下载下来的音乐&#xff0c;只能在本机欣赏&…

纽扣电池/锂电池UN38.3安全检测报告

根据规章要求&#xff0c;航空公司和机场货物收运部门应对锂电池进行运输文件审查&#xff0c;重要的是每种型号的锂电池UN38.3安全检测报告。该报告可由的三方检测机构。如不能提供此项检测报告&#xff0c;将禁止锂电池进行航空运输. UN38.3包含产品&#xff1a;1、 锂电池2…

Typora导出的PDF目录标题自动加编号

Typora导出的PDF目录标题自动加编号 在Typora主题文件夹增加如下文件后&#xff0c;标题便自动加上了编号&#xff1a; https://gitcode.net/as604049322/blog_data/-/blob/master/base.user.css 例如&#xff1a; 但是导出的PDF中&#xff0c;目录却没有编号&#xff1a; 这…

qt day 5

1>实现闹钟功能 ---------------------------------------------------------------------- .pro ---------------------------------------------------------------------- QT core gui texttospeechgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c11# T…

CEF内核和高级爬虫知识

(转)关于MFC中如何使用CEF内核&#xff08;CEF初解析&#xff09; Python GUI: cefpython3的简单分析和应用 cefpython3&#xff1a;一款强大的Python库 开始大多数抓取尝试可以从几乎一行代码开始&#xff1a; fun main() PulsarContexts.createSession().scrapeOutPages(&q…

【项目源码】一套基于springboot+Uniapp框架开发的智慧医院3D人体导诊系统源码

智慧医院3D人体导诊系统源码 开发语言&#xff1a;java 开发工具&#xff1a;IDEA 前端框架&#xff1a;Uniapp 后端框架&#xff1a;springboot 数 据 库&#xff1a;mysql 移 动 端&#xff1a;微信小程序、H5 “智慧导诊”以人工智能手段为依托&#xff0c;为…

JVM介绍

一、介绍 1. JVM是什么 JVM是Java Virtual Machine的缩写&#xff0c;即咱们经常提到的Java虚拟机。虚拟机是一种抽象化的计算机&#xff0c;有着自己完善的硬件架构&#xff0c;如处理器、堆栈等&#xff0c;具体有什么咱们不做了解。目前我们只需要知道想要运行Java文件&…

基于Matlab实现生活中的图像信号分类(附上源码+数据集)

在我们的日常生活中&#xff0c;我们经常会遇到各种各样的图像信号&#xff0c;例如照片、视频、图标等等。对这些图像信号进行分类和识别对于我们来说是非常有用的。在本文中&#xff0c;我将介绍如何使用Matlab来实现生活中的图像信号分类。 文章目录 介绍源码数据集下载 介…

Pinely Round 2 (Div. 1 + Div. 2) G. Swaps(组合计数)

题目 给定一个长度为n(n<1e6)的序列&#xff0c;第i个数ai(1<ai<n)&#xff0c; 操作&#xff1a;你可以将当前i位置的数和a[i]位置的数交换 交换可以操作任意次&#xff0c;求所有本质不同的数组的数量&#xff0c;答案对1e97取模 思路来源 力扣群 潼神 心得 感…

科创板50ETF期权交易:详细规则、费用、保证金和开户攻略

科创板50ETF期权是指以科创板50ETF为标的资产的期权合约。科创板50ETF是由交易所推出的一种交易型开放式指数基金&#xff08;ETF&#xff09;&#xff0c;旨在跟踪科创板50指数的表现&#xff0c;下文介绍科创板50ETF期权交易&#xff1a;详细规则、费用、保证金和开户攻略&am…

2022年09月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:stack or queue 栈和队列都是常用的线性结构,它们都提供两个操作: Push:加入一个元素。 Pop:弹出一个元素。 不同的是,栈是”先进后出”,而队列则是”先进先出”。 给出一个线性结构的进出顺序,判定这个结构是栈还是队列。 时…

RT-Thread I/O设备模型(一)

I/O设备模型 绝大部分的嵌入式系统都包括一些I/O&#xff08;Input/Output&#xff0c;输入/输出&#xff09;设备&#xff0c;例如仪器上的数据显示屏&#xff0c;工业设备上的串口通信、数据采集设备上用于保存数据的 Flash 或 SD 卡&#xff0c;以及网络设备的以太网接口等…

Mapbox-gl 关闭所有Popup,以及关闭按钮出现黑色边框bug

1.官方示例 var popup new mapboxgl.Popup().addTo(map);popup.remove(); 很明显&#xff0c;需要记录popup对象&#xff0c;管理起来比较麻烦。 2.本人采用div的方式关闭所有的popup&#xff0c;在map对象上新增加方法 map.closePopupmapView.popupClear function(){$(&q…

ELK安装、部署、调试(三)zookeeper安装,配置

1.准备 java安装&#xff0c;系统自带即可 2.下载zookeeper zookeeper.apache.org上可以下载 tar -zxvf apache-zookeeper-3.7.1-bin.tar.gz -C /usr/local mv apache-zookeeper-3.7.1-bin zookeeper 3.配置zookeeper mv zoo_sample.cfg zoo.cfg /usr/local/zookeeper/con…