详细介绍React生命周期和diffing算法

news2024/11/28 12:37:13

事件处理

1.通过onXxx属性指定事件处理函数(注意大小写)
React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性;React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ——为了的高效。
2.通过event.target得到发生事件的DOM元素对象 ——不要过度使用ref。

高阶函数和函数的柯里化

高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

function sum(a){
	return(b)=>{
		return (c)=>{
			return a+b+c
		}
	}
}

React生命周期

React组件从创建到死亡它会经历一些特定的阶段。React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

生命周期的三个阶段(旧)

  1. 初始化阶段: 由ReactDOM.render()触发-----------初次渲染
    constructor()
    componentWillMount()
    render()必须使用的一个
    componentDidMount()常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
  2. 更新阶段: 由组件内部this.setState()或父组件重新render触发
    shouldComponentUpdate()
    componentWillUpdate()
    render()
    componentDidUpdate()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    componentWillUnmount()常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息。在这里插入图片描述

重要的钩子

  1. render:初始化渲染或更新渲染调用
  2. componentDidMount:开启监听, 发送ajax请求
  3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

即将废弃的钩子

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate
    16版本使用会出现警告,17版本大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。

生命周期演示

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');
	}

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

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

	//控制组件更新的“阀门”
	shouldComponentUpdate(){
		console.log('Count---shouldComponentUpdate');
		return true// 必须返回true或false
	}

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

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

	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>
		)
	}
}

//父组件A
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>
		)
	}
}

//子组件B
class B extends React.Component{
	//组件将要接收新的props的钩子,第一次不调,更新了才调
	componentWillReceiveProps(props){
		console.log('B---componentWillReceiveProps',props);
	}

	//控制组件更新的“阀门”
	shouldComponentUpdate(){
		console.log('B---shouldComponentUpdate');
		return true
	}
	//组件将要更新的钩子
	componentWillUpdate(){
		console.log('B---componentWillUpdate');
	}

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

	render(){
		console.log('B---render');
		return(
			<div>我是B组件,接收到的车是:{this.props.carName}</div>
		)
	}
}

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

定时器结合生命周期使用:

<div id="test"></div>

<script type="text/babel">
	class Life extends React.Component{
		state = {opacity:1}
		death = ()=>{
			//卸载组件
			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(){
			clearInterval(this.timer)
		}

		//初始化渲染、状态更新之后
		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>

生命周期的三个阶段(新)

  1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
    constructor()
    getDerivedStateFromProps
    render()
    componentDidMount()
  2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
    getDerivedStateFromProps
    shouldComponentUpdate()
    render()
    getSnapshotBeforeUpdate
    componentDidUpdate()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
    componentWillUnmount()
    在这里插入图片描述

生命周期演示

//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
static getDerivedStateFromProps(props,state){
	console.log('getDerivedStateFromProps',props,state);
	return null// 返回状态对象或null
}

//在更新之前获取快照
getSnapshotBeforeUpdate(){
	console.log('getSnapshotBeforeUpdate');
	return 'zagiee'
}
//组件更新完毕的钩子
componentDidUpdate(preProps,preState,snapshotValue){// snapshotValue ='zagiee'
	console.log('Count---componentDidUpdate',preProps,preState,snapshotValue);
}

DOM的diffing算法

虚拟DOM中key的作用

1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】,随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key:
根据数据创建新的真实DOM,随后渲染到到页面

用index作为key可能会引发的问题:

  1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
  2. 如果结构中还包含输入类的DOM:
    会产生错误DOM更新 ==> 界面有问题。
  3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

开发中如何选择key?:

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果确定只是简单的展示数据,用index也是可以的。
在这里插入图片描述

使用index索引值作为key

	初始数据:
			{id:1,name:'小张',age:18},
			{id:2,name:'小李',age:19},
	初始的虚拟DOM<li key=0>小张---18<input type="text"/></li>
			<li key=1>小李---19<input type="text"/></li>

	更新后的数据:
			{id:3,name:'小王',age:20},
			{id:1,name:'小张',age:18},
			{id:2,name:'小李',age:19},
	更新数据后的虚拟DOM<li key=0>小王---20<input type="text"/></li>key相同,内容变了,创建新的真实DOM
			<li key=1>小张---18<input type="text"/></li>
			<li key=2>小李---19<input type="text"/></li>

-----------------------------------------------------------------

使用id唯一标识作为key

	初始数据:
			{id:1,name:'小张',age:18},
			{id:2,name:'小李',age:19},
	初始的虚拟DOM<li key=1>小张---18<input type="text"/></li>
			<li key=2>小李---19<input type="text"/></li>

	更新后的数据:
			{id:3,name:'小王',age:20},
			{id:1,name:'小张',age:18},
			{id:2,name:'小李',age:19},
	更新数据后的虚拟DOM<li key=3>小王---20<input type="text"/></li>
			<li key=1>小张---18<input type="text"/></li>
			<li key=2>小李---19<input type="text"/></li>

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

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

相关文章

数据挖掘,计算机网络、操作系统刷题笔记54

数据挖掘&#xff0c;计算机网络、操作系统刷题笔记54 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;orac…

搭建kafka集群

Kafka集群依赖ZK&#xff0c;需要先启动ZK集群 机器&#xff1a;hadop101,hadoop102, hadoop103 【1】在hadoop101解压&#xff1a; tar -zxvf kafka_2.12-2.4.1.tgz -C ../module/ 【2】在hadoop101修改server.properties配置&#xff1a; #指定broker的id&#xff0c;类似zk…

亚马逊云科技SageMaker:实现自动、可视化管理迭代

现如今&#xff0c;AI正在成为跨时代的技术&#xff0c;在数字经济发展中登上舞台&#xff0c;发挥关键作用。在Gartner发布的《2022年新兴技术成熟度曲线》*报告中&#xff0c;AIGC&#xff08;即AI Generated Content&#xff0c;人工智能自动生成内容&#xff09;被列为2022…

微搭使用笔记(四) 通过循环展示组件+json配置生成表单及数据获取

背景及整体思路 上篇文章我们通过微搭提供的数据模型完成了问卷表单页面的创建和数据采集&#xff0c;相对来说除了数据模型配置略显复杂外其他的倒还算方便。 本文我们通过for循环加上json文件配置的方式实现一个通用表单页面&#xff0c;如果更换了表单只需要替换掉json配置…

stm32 VM8978 音乐播放

一、WAV文件 1、WAV文件简介 2、WAV文件的解析 二、WM8978 1、WM8978介绍 2、WM8978特点 3、WM8978接口 4、WM8978框架 5、 WM8978 寄存器 三、IIS详解 1、IIS介绍 2、 IIS 的特点 3、IIS框架 4、 音频协议 5、 IIS Philips 标准 6、 IIS 时钟 四、音乐播放硬件…

力扣-删除重复的电子邮箱

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;196. 删除重复的电子邮箱二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其…

2.22Linux系统搭建

一.搭建Linux运行环境需要部署Java程序到服务器上,这样程序才能被外面的用户访问到1.安装jdkyum install develop x86_642.安装tomcat1)下载好,通过xshell直接拖到服务器上,依赖了rz命令2)解压缩unzip命令3)使.sh都有可执行权限chmod x *.sh4)启动 sh startup.sh5) 验证 ①ps a…

MAC配置pycharm

Mac配置pycharm 恢复出厂配置 # configuration rm -rf ~/library/preferences/JetBrains/ # caches rm -rf ~/library/caches/JetBrains/ # plugins rm -rf ~/library/application support/JetBrains/ # logs rm -rf ~/library/logs/JetBrains/文件头部 Python #!/usr/bin/e…

Mind+Python+Mediapipe项目——AI健身之跳绳

原文&#xff1a;MindPythonMediapipe项目——AI健身之跳绳 - DF创客社区 - 分享创造的喜悦 【项目背景】跳绳是一个很好的健身项目&#xff0c;为了获知所跳个数&#xff0c;有的跳绳上会有计数器。但这也只能跳完这后看到&#xff0c;能不能在跳的过程中就能看到&#xff0c;…

【Linux】virtualbox获取虚拟机串口日志方法,值得收藏

环境 宿主机&#xff1a;redhat 7.8 virtualbox &#xff1a;6.1.10 虚拟机&#xff1a;UOS 1050u1a x86 一、virtualbox设置 在串口栏中勾选 []启用串口 端口编号选择COM1 端口模式选择裸文件 Port/File Path: 填上 /tmp/box 也就是说我们在宿主机器的/tmp/中创建了vbox的…

C语言知识总结

" "和’ 的比较 " "视为字符串&#xff0c;且编译器在后面自动加上’\0’ 则视为单个字符&#xff0c;整型 1、本质区别 双引号里面的是字符串&#xff0c; 而单引号里面的代表字符。 2、输出区别 str “a”输出的就是a这个字母&#xff1b; str ‘a’…

GSON入门篇(内含教学视频+源代码)

GSON入门篇&#xff08;内含教学视频源代码&#xff09; 教学视频源代码下载链接地址&#xff1a;https://download.csdn.net/download/weixin_46411355/87474475 目录GSON入门篇&#xff08;内含教学视频源代码&#xff09;教学视频源代码下载链接地址&#xff1a;[https://d…

j6-IO流泛型集合多线程注解反射Socket

IO流 1 JDK API的使用 2 io简介 输入流用来读取in 输出流用来写出Out 在Java中&#xff0c;根据处理的数据单位不同&#xff0c;分为字节流和字符流 继承结构 java.io包&#xff1a; File 字节流&#xff1a;针对二进制文件 InputStream --FileInputStream --BufferedInputStre…

【数据结构与算法】字符串1:反转字符串I 反转字符串II 反转字符串里的单词 剑指offer(替换空格、左旋转字符串)

今日任务 344.反转字符串541.反转字符串II剑指Offer 05.替换空格151.反转字符串里的单词剑指Offer58-II.左旋转字符串 1.Leetcode344.反转字符串 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/reverse-string &#…

项目管理工具dhtmlxGantt甘特图入门教程(十一):后端集成问题解决方法

这篇文章给大家讲解如何解决dhtmlxGantt后端集成的问题。 dhtmlxGantt是用于跨浏览器和跨平台应用程序的功能齐全的Gantt图表&#xff0c;可满足应用程序的所有需求&#xff0c;是完善的甘特图图表库 DhtmlxGantt正版试用下载https://www.evget.com/product/4213/download …

联想小新 Air-14 2019IML电脑 Hackintosh 黑苹果efi引导文件

原文来源于黑果魏叔官网&#xff0c;转载需注明出处。硬件型号驱动情况主板Lenovo LNVNB161216处理器Intel Core i5-10210U / i7-10510U已驱动内存8GB DDR4 2666已驱动硬盘康佳KAK0500B128(128 GB/固志硬盘)已驱动显卡Intel UHD 620Nvidia GeForce MX250(屏蔽)无法驱动声卡Cone…

中国社科院与美国杜兰大学金融管理硕士——努力看到别样的风景

卡耐基曾说过&#xff0c;现在的努力是为了换取走更远的路&#xff0c;看到别人看不到的风景。现在卖命是为了让年老的时候&#xff0c;可以不用疲于奔命。对于这段话我深以为然&#xff0c;现在不努力&#xff0c;更待何时呢&#xff0c;就像在职的我们&#xff0c;想发展的更…

编译原理笔记(1)绪论

文章目录1.什么是编译2.编译系统的结构3.词法分析概述4.语法分析概述5.语义分析概述6.中间代码生成和后端概述1.什么是编译 编译的定义&#xff1a;将高级语言翻译成汇编语言或机器语言的过程。前者称为源语言&#xff0c;后者称为目标语言。 高级语言源程序的处理过程&#…

2020蓝桥杯真题回文日期 C语言/C++

题目描述 2020 年春节期间&#xff0c;有一个特殊的日期引起了大家的注意&#xff1a;2020 年 2 月 2 日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202&#xff0c;恰好是一个回文数。我们称这样的日期是回文日期。 有人表示 20200202 是 “千年一遇…

JUC-day03

JUC-day03 线程池: 核心参数(核心线程数 最大线程数 闲置时间 闲置时间单位 阻塞队列 拒绝策略 工厂对象)—理论异步编排: 代码能并行的运行起来—练习(业务能力)流式编程: 串行化编程(List—>数据流—>逻辑一致(过滤器)—>新数据)----练习(编码能力) 1 阻塞队列 1…