【09】基础知识:React组件的生命周期

news2024/11/26 14:35:59

组件从创建到死亡它会经历一些特定的阶段。

React 组件中包含一系列勾子函数(生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子),会在特定的时刻调用。

我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

一、react 生命周期旧

在这里插入图片描述

初始化阶段:由 ReactDOM.render() 触发,初次渲染

1、构造器:constructor()

2、组件将要挂载的钩子:componentWillMount()

3、组件渲染或组件更新的钩子:render()

4、 组件挂载完毕的钩子:componentDidMount()

更新阶段:由组件内部 this.setSate() / this.forceUpdate() 或父组件 render 触发

1、控制组件更新的 “阀门” :shouldComponentUpdate()

2、组件将要更新的钩子:componentWillUpdate()

3、组件渲染或组件更新的钩子:render()

4、组件更新完毕的钩子:componentDidUpdate()

卸载组件:由 ReactDOM.unmountComponentAtNode() 触发

1、组件将要卸载的钩子:componentWillUnmount()

父组件 render:组件 props 值改变触发

1、组件将要接收新的 props 的钩子:componentWillReceiveProps()

二、react 生命周期新

在这里插入图片描述
初始化阶段:由 ReactDOM.render() 触发,初次渲染

1、构造器:constructor()

2、从 props 得到一个派生状态:static getDerivedStateFromProps()

3、组件渲染或组件更新的钩子:render()

4、 组件挂载完毕的钩子:componentDidMount()

更新阶段:由组件内部 this.setSate() / this.forceUpdate() 或父组件 render 触发

1、static getDerivedStateFromProps()

2、控制组件更新的 “阀门” :shouldComponentUpdate()

3、组件渲染或组件更新的钩子:render()

4、在更新之前获取快照:getSnapshotBeforeUpdate()

5、组件更新完毕的钩子:componentDidUpdate()

卸载组件:由 ReactDOM.unmountComponentAtNode() 触发

1、组件将要卸载的钩子:componentWillUnmount()

三、新旧生命周期总结

重要的勾子

1、组件渲染或组件更新的钩子:render()

2、组件挂载完毕的钩子:componentDidMount()

一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

3、组件将要卸载的钩子:componentWillUnmount()

一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

即将废弃的勾子

现在使用会出现警告,下一个大版本需要加上 UNSAFE_ 前缀才能使用,以后可能会被彻底废弃,不建议使用。

1、组件将要挂载的钩子:componentWillMount()

2、组件将要接收新的 props 的钩子:componentWillReceiveProps()

3、组件将要更新的钩子:componentWillUpdate()

四、案例

案例1:引出生命周期

需求:定义组件实现以下功能:

1、让指定的文本做显示 / 隐藏的渐变动画

2、从完全可见,到彻底消失,耗时 2S

3、点击 “不活了” 按钮从界面中卸载组件

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>1_引出生命周期</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		// 创建组件
		class Life extends React.Component {
			state = { opacity: 1 }

			death = () => {
				// clearInterval(this.timer) // 清除定时器(可以卸载componentWillUnmount中)
				ReactDOM.unmountComponentAtNode(document.getElementById('test')) // 卸载组件
			}

			// 组件挂载完毕的钩子
			componentDidMount() {
				console.log('componentDidMount')
				this.timer = setInterval(() => {
					let { opacity } = this.state // 获取原状态
					opacity -= 0.1 // 减小0.1
					if (opacity <= 0) opacity = 1 
					this.setState({ opacity }) // 设置新的透明度
				}, 200)
			}

			// 组件将要卸载的钩子
			componentWillUnmount() {
				console.log('componentWillUnmount')
				clearInterval(this.timer) // 清除定时器
			}
			
			// 初始化渲染、状态更新之后 (state变化会触发render函数,定时器如果写在render中,会造成无限递归)
			render() {
				console.log('render')
				return (
					<div>
						<h2 style={{ opacity: this.state.opacity }}>React学不会怎么办?</h2>
						<button onClick={this.death}>不活了</button>
					</div>
				)
			}
		}

		// 渲染组件
		ReactDOM.render(<Life />, document.getElementById('test'))
	</script>
</body>
</html>

案例二:React 生命周期旧

累加器,点击数值+1

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期(旧)</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//  创建组件
		class Count extends React.Component {
			// 构造器
			constructor(props) {
				console.log('Count---constructor')
				super(props)
				this.state = { count: 0 } // 初始化状态
			}

			// 加1按钮的回调
			add = () => {
				const { count } = this.state
				this.setState({ count: count+1 }) // 更新状态
			}

			// 卸载组件按钮的回调
			death = () => {
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			// 强制更新按钮的回调
			force = () => {
				this.forceUpdate()
			}

			// 组件将要挂载的钩子
			componentWillMount() {
				console.log('Count---componentWillMount')
			}

			// 控制组件更新的 “阀门” 
			shouldComponentUpdate() {
				console.log('Count---shouldComponentUpdate')
				// 不写时,默认值为true,代表允许组件更新;写了以后,必须有返回值Boolan,true/false
				return true
			}

			// 组件将要更新的钩子
			componentWillUpdate() {
				console.log('Count---componentWillUpdate')
			}

			// 组件渲染或组件更新的钩子
			render() {
				console.log('Count---render')
				const { count } = this.state
				return (
					<div>
						<h2>当前求和为:{ count }</h2>
						<button onClick={this.add}>点我+1</button>
						<button onClick={this.death}>卸载组件</button>
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				)
			}

			// 组件挂载完毕的钩子
			componentDidMount() {
				console.log('Count---componentDidMount')
			}

			// 组件更新完毕的钩子
			componentDidUpdate() {
				console.log('Count---componentDidUpdate')
			}

			// 组件将要卸载的钩子
			componentWillUnmount() {
				console.log('Count---componentWillUnmount')
			}
		}

		// 渲染组件
		ReactDOM.render(<Count />, document.getElementById('test'))
	</script>
</body>
</html>

父组件 render 触发子组件 props 值改变

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期(旧)</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="car"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		// 父组件
		class A extends React.Component {
			// 初始化状态
			state = { carName: '奔驰' }

			changeCar = () => {
				this.setState({ carName: '奥拓' })
			}

			render() {
				return (
					<div>
						<div>我是A组件</div>
						<button onClick={this.changeCar}>换车</button>
						<B carName={this.state.carName}/>
					</div>
				)
			}
		}

		// 子组件
		class B extends React.Component {
			// 组件将要接收新的props的钩子(props第一次接收值时不触发)
			componentWillReceiveProps(props) {
				console.log('B---componentWillReceiveProps', props)
			}

			// 控制组件更新的 “阀门” 
			shouldComponentUpdate() {
				console.log('B---shouldComponentUpdate')
				// 不写时,默认值为true,代表允许组件更新;写了以后,必须有返回值Boolan,true/false
				return true
			}

			// 组件将要更新的钩子
			componentWillUpdate() {
				console.log('B---componentWillUpdate')
			}

			// 组件渲染或组件更新的钩子
			render() {
				console.log('B---render')
				const { carName } = this.props
				return (
					<div>我是B组件,接收到的车是:{carName}</div>
				)
			}

			// 组件更新完毕的钩子
			componentDidUpdate() {
				console.log('Count---componentDidUpdate')
			}
		}

		// 渲染组件
		ReactDOM.render(<A />, document.getElementById('car'))
	</script>
</body>
</html>

案例三:React 生命周期新

新生命周期新增方法:

static getDerivedStateFromProps() 从props得到一个派生状态,此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props 。派生状态会导致代码冗余。

getSnapshotBeforeUpdate() 在更新之前获取快照,此用法并不常见。它使得组件能在发生改变之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>3_react生命周期(新)</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		// 创建组件
		class Count extends React.Component {
			// 构造器
			constructor(props) {
				console.log('Count---constructor')
				super(props)
				this.state = { count: 0 } // 初始化状态
			}

			// 加1按钮的回调
			add = () => {
				const { count } = this.state
				this.setState({ count: count+1 }) // 更新状态
			}

			// 卸载组件按钮的回调
			death = () => {
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			// 强制更新按钮的回调
			force = () => {
				this.forceUpdate()
			}

			// 从props得到一个派生状态:若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
			static getDerivedStateFromProps(props, state) {
				console.log('getDerivedStateFromProps', props, state)
				return null // 必须有返回值,状态对象或者null
			}

			// 在更新之前获取快照
			getSnapshotBeforeUpdate() {
				console.log('getSnapshotBeforeUpdate')
				return 'atguigu' // 必有有返回值,快照或者null,将作为参数传递给 componentDidUpdate()
			}

			// 控制组件更新的 “阀门” 
			shouldComponentUpdate() {
				console.log('Count---shouldComponentUpdate')
				// 不写时,默认值为true,代表允许组件更新;写了以后,必须有返回值Boolan,true/false
				return true
			}

			// 组件渲染或组件更新的钩子
			render() {
				console.log('Count---render')
				const { count } = this.state
				return (
					<div>
						<h2>当前求和为:{ count }</h2>
						<button onClick={this.add}>点我+1</button>
						<button onClick={this.death}>卸载组件</button>
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				)
			}

			// 组件挂载完毕的钩子
			componentDidMount() {
				console.log('Count---componentDidMount')
			}

			// 组件更新完毕的钩子(接收参数:之前的的props、之前的state、传过来的快照)
			componentDidUpdate(prevProps, prevState, snapshotValue) {
				console.log('Count---componentDidUpdate', prevProps, prevState, snapshotValue)
			}

			// 组件将要卸载的钩子
			componentWillUnmount() {
				console.log('Count---componentWillUnmount')
			}

		}

		//渲染组件
		ReactDOM.render(<Count count={ 199 } />, document.getElementById('test'))
	</script>
</body>
</html>

案例四:getSnapShotBeforeUpdate 的使用场景

展示新闻列表,1s向上追加一条新闻,并保证页面视图区域内容不变。

思路:

利用 getSnapShotBeforeUpdate() 获取组件更新之前 内容的 scrollHeight,传递给 componentDidUpdate()

组件更新之后,设置当前容器的 scrollTop 值为,当前内容高度 - 组件更新之前内容高度

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>4_getSnapShotBeforeUpdate的使用场景</title>
	<style>
		.list {
			width: 200px;
			height: 150px;
			background-color: skyblue;
			overflow: auto;
		}

		.news {
			height: 30px;
		}
	</style>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>

	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		class NewsList extends React.Component {
			state = { newsArr: [] }

			componentDidMount() {
				setInterval(() => {
					const { newsArr } = this.state // 获取原状态
					const news = '新闻' + (newsArr.length + 1) // 模拟一条新闻
					this.setState({ newsArr: [news, ...newsArr] }) // 更新状态
				}, 1000)
			}

			getSnapshotBeforeUpdate() {
				return this.refs.list.scrollHeight
			}

			componentDidUpdate(preProps, preState, height) {
				this.refs.list.scrollTop += this.refs.list.scrollHeight - height
			}

			render() {
				return (
					<div className="list" ref="list">
						{
							this.state.newsArr.map((n, index) => {
								return <div key={index} className="news">{n}</div>
							})
						}
					</div>
				)
			}

		}

		ReactDOM.render(<NewsList />, document.getElementById('test'))
	</script>
</body>
</html>

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

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

相关文章

leetcode做题笔记173. 二叉搜索树迭代器

实现一个二叉搜索树迭代器类BSTIterator &#xff0c;表示一个按中序遍历二叉搜索树&#xff08;BST&#xff09;的迭代器&#xff1a; BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在…

排序优化:如何实现一个通用的、高性能的排序函数?

文章来源于极客时间前google工程师−王争专栏。 几乎所有的编程语言都会提供排序函数&#xff0c;比如java中的Collections.sort()。在平时的开发中&#xff0c;我们都是直接使用&#xff0c;这些排序函数是如何实现的&#xff1f;底层都利用了哪种排序算法呢&#xff1f; 问题…

微信小程序入门---超详细教程

一&#xff0c;小程序入门 1.1 什么是小程序&#xff1f; 2017年度百度百科十大热词之一 微信小程序&#xff08;wei xin xiao cheng xu&#xff09;&#xff0c;简称小程序&#xff0c;英文名Mini Program&#xff0c;是一种不需要下载安装即可使用的应用( 张小龙对其的定义…

好的摄影师都会iPhone 8和iOS 11的这三项功能

众所周知&#xff0c;苹果的手机像素一直处于智能手机摄影的前沿&#xff0c;在即将到来的九月&#xff0c;苹果公司准备证明他拥有最好的相机技术。 虽然我们还不知道iPhone 8摄像头的具体细节&#xff0c;如几百万像素、光学变焦是多少&#xff0c;但我们确实知道苹果正在给i…

2023年全球团队协作工具排名推荐,这6款值得关注!

随着远程工作变得越来越普遍&#xff0c;团队协作工具在今天的工作场所变得越来越重要。然而&#xff0c;找到合适的协作工具来满足团队的需求可能是一个挑战。有这么多可用的选项&#xff0c;很难决定哪一个对您的团队最有效。 在本文中&#xff0c;我们将研究团队协作工具的不…

小程序的入门

目录 小程序的简介 好处 安装及使用 小程序的入门案列 小程序的简介 微信小程序是一种轻量级的应用程序&#xff0c;可以在微信平台上运行。它们具有快速、便捷和低成本等特点。通过微信小程序&#xff0c;用户可以在微信内直接使用各种功能&#xff0c;而无需下载和安装额外…

如何降低海康、大华等网络摄像头调用的高延迟问题(一):海康威视网络摄像头的python sdk使用(opencv读取sdk流)

目录 1.python sdk使用 1.海康SDK下载 2.opencv读取sdk流 先说效果&#xff0c;我是用的AI推理的实时流&#xff0c;延迟从高达7秒降到小于1秒 如果觉得这个延迟还不能接受&#xff0c;下一章&#xff0c;给大家介绍点上不得台面的小方法 SDK&#xff08;Software Developme…

“小程序:改变电商行业的新趋势“

目录 引言1. 小程序的简介1.1 什么是小程序&#xff1f;1.2 小程序的优势 2. 小程序之电商演示1.注册微信小程序2.安装开发工具3.创建项目 3. 小程序之入门案例总结 引言 随着移动互联网的迅猛发展&#xff0c;小程序作为一种全新的应用形态&#xff0c;正在逐渐改变着传统电商…

springboot 志同道合交友网站演示

springboot 志同道合交友网站演示 liu1113625581

SpringBoot面试题2:SpringBoot与SpringCloud 区别?SpringBoot和Spring、SpringMVC的区别

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:SpringBoot与SpringCloud 区别? Spring Boot 和 Spring Cloud 是 Spring 生态系统中的两个关键组件,它们有以下区别: 定位:Spring Boot 用于简…

<三>Qt斗地主游戏开发:主界面初始化显示

1. 主界面效果 效果关键点&#xff1a; 1&#xff09;拖动标题栏可实现主界面拖动 2&#xff09;logo图标名称及主界面背景 3&#xff09;最小化及关闭 2.思路分析 1&#xff09;背景图片及logo图标的设定比较简单&#xff0c;通过stylesheet即可实现。通过QWidget的拖动即可实…

Jboss反序列化漏洞

run.bat运行jboss 看下server.xml 端口设置的多少 打开jboss 用jboss反序列工具进行扫描 执行命令&#xff0c;因为存在jboss存在漏洞&#xff0c;所以执行命令得到结果 找一下jboss的目录 dir /s c:\*.jsp 先选一个jboss目录上传试一下 把斜杠改成反斜杠 给这个目录上传一个脚…

01背包问题 : 二维dp数组 + 图文

其实01背包问题&#xff0c;我之前跟着代码随想录的Carl学过&#xff0c;今天我看到另外一种定义dp数组的方式&#xff0c;我觉得思路也不错&#xff0c;所以我又来写一篇&#xff0c;大家再看此篇之后也可以看我的往期文章&#xff0c;非常感谢您的阅读&#xff1a;解决0-1背包…

「网络编程」网络层协议_ IP协议学习_及深入理解

「前言」文章内容是网络层的IP协议讲解。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、IP协议简介二、IP协议报头三、IP网段划分&#xff08;子网划分&#xff09;四、特殊的IP地址五、IP地址的数量限制六、私有IP地址和公网IP地址七、路由八、分…

Unity实现摄像机向屏幕中间发射射线射击物体

1.创建一个准星放在屏幕中间 外部找个PNG透明图&#xff0c;拖到Unity文件夹&#xff0c;右上角改成精灵sprite2d 2.添加到UI画布 3.写脚本 首先&#xff0c;我们需要引入一些 "工具"&#xff0c;就像我们在玩游戏时要先下载游戏客户端一样。这里的 "工具&quo…

【Python】Python语言基础(中)

第十章 Python的数据类型 基本数据类型 数字 整数 整数就是整数 浮点数 在编程中&#xff0c;小数都称之为浮点数 浮点数的精度问题 print(0.1 0.2) --------------- 0.30000000000000004 ​​1.可以通过round()函数来控制小数点后位数 round(a b)&#xff0c;则表示…

华为云云耀云服务器L实例评测|华为云耀云服务器L实例启动宠物预约项目(九)

十、修改配置文件&#xff0c;启动宠物预约项目&#xff1a; 上面步骤进行了程序的安装&#xff0c;接下来就需要对相关程序的配置进行修改&#xff0c;如修改PHP-FPM的运行方式&#xff0c;增加nginx的配置文件&#xff0c;修改Laravel的配置文件。 1. 修改PHP-FPM的配置&…

【LeetCode: 136. 只出现一次的数字 | 位运算 - 异或】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

git强制删除本地分支 git branch -D

git强制删除本地分支 git branch -D git删除本地分支_zhangphil的博客-CSDN博客git branch -d <分支名>可以通过: git branch 查看所有本地分支及其名字&#xff0c;然后删除特定分支。https://blog.csdn.net/zhangphil/article/details/82255002 使用git branch -d删除…

网络工程师知识点3

41、各个路由协议&#xff0c;在华为设备中的优先级&#xff1f; 直连路由 0 OSPF 10 静态 60 42、OSPF&#xff1a;开放式最短路径优先路由协议&#xff0c;使用SPF算法发现和计算路由 OSPF的优点&#xff1a; 1、收敛速度快&#xff0c;无路由自环&#xff0c;适用于大型网络…