【react全家桶学习】react的 (新/旧) 生命周期(重点)
目录
生命周期(旧)
挂载时的生命周期
constructor(props)
componentWillMount()-------------新生命周期已替换
render()
componentDidMount()--- 组件挂载完毕的钩子
渲染时的生命周期
componentWillReceiveProps (nextProps)------------------新生命周期已替换 ,父组件渲染的时候子组件会调用,组件将要接收新的props的钩子
shouldComponentUpdate(nextProps,nextState)----调用setState()时会调用,强制更新则不会触发该钩子
componetnWillUpdate(nextProps,nextState)----------------新生命周期已替换
render()
componentDidUpdate(prevProps,precState,snapshot)
方式一【调用setState触发的钩子】
方式二【调用forceUpdate触发的钩子】
生命周期(旧)总结:
生命周期(新)
react新旧生命周期区别
挂载时的生命周期
constructor --上面已讲
getDerivedStateFromProps --详细讲解
render --上面已讲
componentDidMount --上面已讲
渲染时的生命周期
getDerivedStateProps --上面已讲
shouldComponentUpdate -- 控制组件更新的开关,上面已讲
render --上面已讲
getSnapshotBeforeUpdate -- 详细讲解
componentDidUpdate--上面已讲
卸载时的生命周期
componentWillUnmount --同旧的一样,不讲喽
生命周期(新)总结:
1、初始化阶段: 由ReactDOM.render()触发---初次渲染
2,更新阶段: 由组件内部this.setSate()或父组件重新render触发
3,卸载组件: 由ReactDOM.unmountComponentAtNode()触发
重要的钩子
即将废弃的子
相对比vue的生命周期,react显得复杂的多,光从名称上就比vue长,所以做好准备,不要放弃,坚持就是胜利、
文章有点长,不要着急,常用的其实没几个,看到最后的大总结,千万不要错过呀~
React的生命周期可以分为三个阶段:挂载、渲染、卸载;
生命周期(旧)
挂载时的生命周期
以下面这个例子来讲解 ;
import React, { Component } from 'react'export default class oldIndex extends Component {constructor(props) {console.log('constructor')super(props)this.state = { count: 0 }}add = () => {const { count } = this.statethis.setState({ count: count++ })}// 组件将要挂载的钩子componentWillMount() {console.log('componentWillMount')}// 组件挂载完毕的钩子componentDidMount() {console.log('componentDidMount')}render() {console.log('render')const { count } = this.statereturn (<div><h2>当前求和为:{count}</h2><button onClick={this.add}>点我+1</button></div>)}
}
看下挂载时的生命周期打印顺序:
综上所述【挂载时】旧生命周期 调用顺序如下:
-
constructor(props)
接收props和context,当想在函数内使用这两个参数需要在super传入参数,当使用constructor时必须使用super,否则可能会有this的指向问题,如果不初始化state或者不进行方法绑定,则可以不在组件写构造函数;
注意:避免将 props 的值复制给 state!这是一个常见的错误
constructor(props) {super(props);// 不要这样做this.state = { color: props.color };
}
如此做毫无必要(可以直接使用 this.props.color
),同时还产生了 bug(更新 prop 中的 color
时,并不会影响 state)。
-
componentWillMount()-------------新生命周期已替换
在挂载之前也就是render之前被调用。
在服务端渲染唯一会调用的函数,代表已经初始化数据但是没有渲染dom,因此在此方法中同步调用 setState()
不会触发额外渲染。
-
render()
render函数会插入jsx生成的dom结构,react会生成一份虚拟dom树,在每一次组件更新时,在此react会通过其diff算法比较更新前后的新旧DOM树,比较以后,找到最小的有差异的DOM节点,并重新渲染。
-
componentDidMount()--- 组件挂载完毕的钩子
在组件挂在后(插入到dom树中)后立即调用
可以在这里调用Ajax请求,返回的数据可以通过setState使组件重新渲染,或者添加订阅,但是要在conponentWillUnmount中取消订阅
渲染时的生命周期
当组件的 props 或 state 发生变化时会触发更新。
-
componentWillReceiveProps (nextProps)------------------新生命周期已替换 ,父组件渲染的时候子组件会调用,组件将要接收新的props的钩子
创建一个父组件
import React, { Component } from 'react'
import Child from './child'
export default class index extends Component {state = {name: '小锁',}changeName = () => {this.setState({name: '大锁',})}render() {return (<div><h2>父组件</h2><button onClick={this.changeName}>改名</button><Child name={this.state.name}></Child></div>)}
}
子组件child.jsx
在子组件中打印该钩子,看父组件触发后是否会调用
import React, { Component } from 'react'export default class child extends Component {componentWillReceiveProps() {console.log('componentWillReceiveProps')}render() {return <div>{this.props.name}</div>}
}
很显然调用父组件的改名方法时,子组件的钩子也对应触发了
注意:子组件在刚进来的时候是不会调用的,只有当在父组件中更改了状态state值,才会重新触发子组件的render才会算一次调用。
该钩子还能接收参数:我们传入props
打印看效果:
-
shouldComponentUpdate(nextProps,nextState)----调用setState()时会调用,强制更新则不会触发该钩子
在渲染之前被调用,默认返回为true,在state发生变化时,都会去调用该钩子 。
不写该钩子默认返回true,写了就以你写的为主,必须要有返回值且是一个布尔值,否则会报错,返回true就正常进行,返回false时,当state更改,页面也不会更新了
可以看到每次state更新都会触发 shouldComponentUpdate钩子函数
-
componetnWillUpdate(nextProps,nextState)----------------新生命周期已替换
当组件接收到新的props和state会在渲染前调用,初始渲染不会调用该方法。
shouldComponentUpdate返回true以后,组件进入重新渲染的流程,进入componentWillUpdate,不能在这使用setState,在函数返回之前不能执行任何其他更新组件的操作
点击加1
-
render()
-
componentDidUpdate(prevProps,precState,snapshot)
点击加1,在更新之后立即调用,首次渲染不会调用,之后每次重新渲染都会被调用。
方式一【调用setState触发的钩子】
从上面的打印结果我们可以看到,当调用了setState之后会触发以下三个钩子函数
注意:可以在componentDidUpdate方法调用setState,但是要包含在条件语句中,否则一直更新会造成死循环
当组件更新后,可以在此处对 DOM 进行操作。如果对更新前后的props进行了比较,可以进行网络请求。(当 props 未发生变化时,则不会执行网络请求)。
componentDidUpdate(props) {console.log('componentDidUpdate')// 典型用法(不要忘记比较 props):if (this.props.userID !== props.userID) {this.fetchData(this.props.userID)}}
方式二【调用forceUpdate触发的钩子】
当我不修改state状态只想更新一下,就不走shouldComponentUpdate了,只走以下2个钩子函数
点击强制更新可以看到触发了这两个生命周期
生命周期(旧)总结:
1.初始化阶段: 由 ReactDOM.render()触发---初次染
- constructor()
- componentWillMount()
- render()
- componentDidMount()----【常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息】
2.更新阶段: 由组件内部 this.setState()或父组件重新 render 触发
- shouldComponentUpdate()
- componentWillUpdate()
- render()----【必须常用】
- componentDidUpdate()
3.卸载组件:由 ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()----【常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息】
生命周期(新)
react新旧生命周期区别
新生命周期增加钩子:getDerivedStateFromProps、getSnapshotBeforeUpdate(也不常用)
在新版本中也可以用旧的生命周期,但会警告提示甚至报错:
所以对于这三个钩子:componentWillMount、componentWillUpdate、componentWillReceiveProps 需要加上 UNSAFE_ 前缀才行
总结:
新生命周期删除三个钩子:componentWillMount、componentWillUpdate、componentWillReceiveProps 这三个钩子在17.版本使用时要加上前缀UNSAFE_,即UNSAFE_componentWillMoun否则会有警告甚至报错。
这些生命周期增加使用成本,减少程序员使用。这是因为这些生命周期方法经常被误解和滥用,UNSAFE_不是指不安全,而是在未来版本中(maybe 18.xx版本中)可能出现bug,特别是异步渲染中。实际很少使用这三个钩子,基本不用的。所以了解即可。
挂载时的生命周期
-
constructor --上面已讲
-
getDerivedStateFromProps --详细讲解
这个生命周期的意思就是从props中获取state
,可以说是太简单易懂了。可以说,这个生命周期的功能实际上就是将传入的props映射到state上面
。
由于16.4的修改,这个函数会在每次re-rendering之前被调用
,这意味着什么呢?
意味着即使你的props没有任何变化,而是父state发生了变化,导致子组件发生了re-render,这个生命周期函数依然会被调用。看似一个非常小的修改,却可能会导致很多隐含的问题。
这个生命周期函数是为了替代componentWillReceiveProps
存在的,所以在你需要使用componentWillReceiveProps
的时候,就可以考虑使用getDerivedStateFromProps
来进行替代了。
当我们直接去使用的会报错:
报错内容的意思就是:该生命周期不能作为一个实例方法去调用,应该将它声明为静态方法,需要加上static关键字
解决:
可以打印了,但仍然报错,意思是:该生命周期必须要有返回值,可以是两种情况,一种是状态对象,或者是null,但没有返回值不行。
我们返回一个状态对象,试一下:
看页面效果,当返回一个状态对象后,我们再去通过点我加1改变count值,值是不会被改变的
说明当我们返回一个状态对象后,会影响状态更新,并且不会以初始化为主,就会以它返回的为主,并且以后也都改不了了。
那我们在这里传入一个count
在该钩子进行接收,并返回props
那么页面就会优先使用该状态,且不可更改。 此时就验证了官网所说,使用了该生命周期后,state的值在任何时候都取决于props
这就体现了该生命周期的含义,从props那得到一个衍生的状态。
需要注意的是,它可以接收2个参数,一个是props,一个是state,如果props传入的内容不需要影响到你的state,那么就需要返回一个null,这个返回值是必须的,所以尽量将其写到函数的末尾。
static getDerivedStateFromProps(props, state) {console.log(props, state)const { count } = propsif (count !== state.count) {return {count,}}return null}
使用场景就是:
(1)若state的值在任何时候都取决于props,可以使用,也不是必须
(2)可以通过对比props中某个属性的值,和state中的值,在不同的情况下使用不同的状态。
总之:也不太建议使用,派生状态会导致代码冗余,并使组件难以维护,了解即可
-
render --上面已讲
-
componentDidMount --上面已讲
渲染时的生命周期
-
getDerivedStateProps --上面已讲
-
shouldComponentUpdate -- 控制组件更新的开关,上面已讲
-
render --上面已讲
-
getSnapshotBeforeUpdate -- 详细讲解
当我们点击加1,进行渲染的时候,该生命周期就会报错
此时上面的警告就是需要一个返回值,返回null或者一个snapshot(快照值--字符串、数组、对象、函数都可作为快照值)
因此我们可以在更新前获取快照,然后再组件更新完毕的时候可以获取快照:
使用场景:例如在列表没更新前我们想获取当前10条数据的高度,这时候就可以通过快照保存,在更新之后变为11条,照样可以拿到之前的列表高度。
// 在更新之前获取快照getSnapshotBeforeUpdate() {console.log('getSnapshotBeforeUpdate')let { count } = this.statereturn 'suosuo'}// 组件更新完毕的钩子componentDidUpdate(prePops, preState, snapshotValue) {console.log('componentDidUpdate', prePops, preState, snapshotValue)}
使用场景 :例如 列表内容定时自动加一条,当滚动到某个位置时,停留在此位置
原理:我们就可以通过getSnapshotBeforeUpdate生命周期记录当前
import React, { Component } from 'react'
import './demo.css'export default class demo extends Component {state = { newsArr: [] }componentDidMount() {setInterval(() => {const { newsArr } = this.stateconst news = '哈哈' + (newsArr.length + 1)this.setState({newsArr: [news, ...newsArr],})}, 1000)}//保存更新列表前的列表的高度getSnapshotBeforeUpdate() {return this.refs.list.scrollHeight}componentDidUpdate(preProps, preState, height) {//此时滚动条的滚动的位置就加等于当前列表高度减去保存之前列表高度//this.refs.list.scrollHeight - height其实就是一条消息的高度//因此要想一直停留在此处,得用+=this.refs.list.scrollTop += this.refs.list.scrollHeight - height}render() {return (<div className="list" ref="list">{this.state.newsArr.map((n, i) => {return (<div className="news" key={i}>{n}</div>)})}</div>)}
}
效果:此时就可以看到,我们悬浮到哪条信息的位置,就会停留在哪,即便数据仍在添加,也不影响
-
componentDidUpdate--上面已讲
卸载时的生命周期
-
componentWillUnmount --同旧的一样,不讲喽
生命周期(新)总结:
1、初始化阶段: 由ReactDOM.render()触发---初次渲染
- constructor()
- getDerivedStateFromProps
- render()
- componentDidMount() --常用
2,更新阶段: 由组件内部this.setSate()或父组件重新render触发
- getDerivedStateFromProps
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()
3,卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount() --常用
重要的钩子
- render:初始化渲染或更新渲染调用
- componentDidMount:开启监听,发送ajax请求
- componentWillUnmount:做一些收尾工作,如:清理定时器
即将废弃的子
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
现在使用会出现警告,下一个大版本需要加上 UNSAFE_前缀才能使用,以后可能会被彻底
废弃,不建议使用。
本文主要参考链接:
react生命周期详细介绍_小薯片子的博客-CSDN博客
React新生命周期--getDerivedStateFromProps - 简书
相关文章:

【react全家桶学习】react的 (新/旧) 生命周期(重点)
目录 生命周期(旧) 挂载时的生命周期 constructor(props) componentWillMount()-------------新生命周期已替换 render() componentDidMount()--- 组件…...
Gradio私网和公网的使用
Gradio私网问题 如果部署的服务器只有私有地址,那么无法直接从外部网络中的其他计算机访问该服务器和其中运行的 Gradio 应用程序。在这种情况下,你可以考虑使用端口转发技术,将服务器的私有地址映射到一定的公开地址上,从而可以…...

ant design vue 配置菜单外部打开
实现如下 菜单配置 前端项目地址:http://localhost:3000 菜单路径:dataCenter/HealthData 打开方式:外部 在项目中src-->config-->router.config.js文件 将需要再外部打开的菜单地址进行如下配置 菜单地址:/dataCenter/Hea…...

YOLOv5/v7 添加注意力机制,30多种模块分析⑦,CCN模块,GAMAttention模块
目录 一、注意力机制介绍1、什么是注意力机制?2、注意力机制的分类3、注意力机制的核心 二、CCN模块1、CCN模块的原理2、实验结果3、应用示例 三、GAMAttention模块1、GAMAttention模块的原理2、实验结果3、应用示例 大家好,我是哪吒。 🏆本…...

IDEA下Logback.xml自动提示功能配置
首先打开logback的配置文件,在configuration标签中加入xsd的配置 <configuration xmlns"http://ch.qos.logback/xml/ns/logback"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://ch.qos.logback/xml…...
CUDA编程模型系列八(原子操作 / 规约 / 向量元素求和)
本系列视频目的是帮助开发者们一步步地学会利用CUDA编程模型加速GPU应用, 我们的口号是: 让GPU飞起来 本期我介绍了cuda 当中规约算法的一种情况, 也是小何尚职业生涯中的第一道面试题, 计算数组中所有元素的和. CUDA编程模型系列八(原子操作 / 规约 / 向量元素求和) #include…...
go语言系列基础教程总结(4)
1、goroutine和channel 每执行一次go func()就创建一个 goroutine,包含要执行的函数和上下文信息。 goroutine 是Go程序并发的执行体,channel是它们之间的沟通连接通道。 var ch1 chan int. //声明一个整型的通道 2、channel 常用操作 //定义一个…...

网络基础一:网络协议初识与网络传输基本流程
目录 网络协议认识“协议”网络协议初识协议分层OSI七层模型(理论模型)TCP/IP五层(或四层)模型(工程实现模型) 网络中的地址管理MAC地址IP地址 网络传输基本流程路由的本质 数据包封装和分用网络协议需要解决的问题 网络协议 计算…...

Mysql找出执行慢的SQL【慢查询日志使用与分析】
分析慢SQL的步骤 慢查询的开启并捕获:开启慢查询日志,设置阈值,比如超过5秒钟的就是慢SQL,至少跑1天,看看生产的慢SQL情况,并将它抓取出来explain 慢SQL分析show Profile。(比explain还要详细…...

设计模式3:单例模式:JMM与volatile和synchronized的关系
本文目录 JMM简介Java 内部内存模型(The Internal Java Memory Model)硬件内存架构(Hardware Memory Architecture)弥合 Java 内存模型和硬件内存架构之间的差距(Bridging The Gap Between The Java Memory Model And The Hardware Memory Architecture)1.共享对象的可见性2.竞…...
一个简单的OPC UA/ModbusTCP 网关(Python)
使用我前面几篇博文的内容,能够使用Python编写一个最简单的OPC UA /ModbusTCP网关。 从这个程序可以看出: 应用OPC UA 并不难,现在我们就可以应用到工程应用中,甚至DIY项目也可以。不必采用复杂的工具软件。使用Python 来构建工…...

线性代数行列式的几何含义
行列式可以看做是一系列列向量的排列,并且每个列向量的分量可以理解为其对应标准正交基下的坐标。 行列式有非常直观的几何意义,例如: 二维行列式按列向量排列依次是 a \mathbf{a} a和 b \mathbf{b} b,可以表示 a \mathbf{a} a和…...

python用flask将视频显示在网页上
注意我们的return返回值必须是以下之一,否则会报错 from flask import Flask, render_template, Response import cv2app Flask(__name__)app.route(/) def index():return render_template(index.html)def gen(camera):while True:success, image camera.read(…...

【数据挖掘】时间序列教程【一】
第一章 说明 对于时间序列的研究,可以追溯到19世纪末和20世纪初。当时,许多学者开始对时间相关的经济和社会现象进行研究,尝试发现其规律和趋势。其中最早的时间序列研究可以追溯到法国经济学家易贝尔(Maurice Allais)…...
优化索引粒度参数提升ClickHouse查询性能
当对高基数列进行过滤查询时,总是希望尽可能跳过更多的行。否则需要处理更多数据、需要更多资源。ClickHouse缺省在MergeTree表读取8192行数据块,但我们可以在创建表时调整该index_granularity 参数。本文通过示例说明如何调整该参数优化查询性能。 inde…...

selenium\webdriver\remote\errorhandler.py:242: SessionNotCreatedException问题解决
报错信息: raise exception_class(message, screen, stacktrace) E selenium.common.exceptions.SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 112 E Current browser versi…...

MySQL 备份与恢复
MySQL 备份与恢复 一、数据库备份的分类1.1 数据备份的重要性1.2 数据库备份的分类1.2.1 从物理与逻辑的角度,分为物理备份和逻辑备份1.2.2 从数据库的备份策略角度,分为完全备份,差异备份和增量备份1.2.3 常见的备份方法 二、MySQL完全备份与…...

js中改变this指向的三种方式
js中改变this指向的三种方式 1、call方法2、apply方法3、bind方法 1、call方法 使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示: <script>const obj {uname: 刘德华}function fn(x, y) {console.log(this) …...
小程序中如何进行数据传递和通信
103. 小程序中如何进行数据传递和通信? 1. 使用页面参数传递数据: 在小程序中,可以通过页面参数来传递数据。当跳转到一个新页面时,可以将需要传递的数据作为参数传入,然后在目标页面的onLoad函数中获取参数。 示例…...

Vue3项目中引入ElementUI使用详解
目录 Vue3项目中引入 ElementUI1.安装2.引入2.1 全局引入2.2 按需引入viteWebpack 3.使用 Vue3项目中引入 ElementUI ElementUI是一个强大的PC端UI组件框架,它不依赖于vue,但是却是当前和vue配合做项目开发的一个比较好的ui框架,其包含了布局…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
代码随想录刷题day30
1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

【堆垛策略】设计方法
堆垛策略的设计是积木堆叠系统的核心,直接影响堆叠的稳定性、效率和容错能力。以下是分层次的堆垛策略设计方法,涵盖基础规则、优化算法和容错机制: 1. 基础堆垛规则 (1) 物理稳定性优先 重心原则: 大尺寸/重量积木在下…...