详细介绍React生命周期和diffing算法
事件处理
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组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
生命周期的三个阶段(旧)
- 初始化阶段: 由ReactDOM.render()触发-----------初次渲染
constructor()
componentWillMount()
render()必须使用的一个
componentDidMount()常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息 - 更新阶段: 由组件内部this.setState()或父组件重新render触发
shouldComponentUpdate()
componentWillUpdate()
render()
componentDidUpdate() - 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
componentWillUnmount()常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息。
重要的钩子
- render:初始化渲染或更新渲染调用
- componentDidMount:开启监听, 发送ajax请求
- componentWillUnmount:做一些收尾工作, 如: 清理定时器
即将废弃的钩子
- componentWillMount
- componentWillReceiveProps
- 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.statereturn(<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.1if(opacity <= 0) opacity = 1this.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>
生命周期的三个阶段(新)
- 初始化阶段: 由ReactDOM.render()触发—初次渲染
constructor()
getDerivedStateFromProps
render()
componentDidMount() - 更新阶段: 由组件内部this.setSate()或父组件重新render触发
getDerivedStateFromProps
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate
componentDidUpdate() - 卸载组件: 由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可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。 - 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。 - 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用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>
相关文章:

详细介绍React生命周期和diffing算法
事件处理 1.通过onXxx属性指定事件处理函数(注意大小写) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性;React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ——为了的高效。 2.通过event.target得到发生事件的DOM…...

面向对象的特点
1、什么是对象对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物。在面向对象程序设计中,对象所指的是计算机系统中的某一个成分。在面向对象程序设计中,对象包含两个含义,其中一个是数据,另外一个…...

智慧校园平台源码 智慧教务 智慧电子班牌系统
系统介绍 智慧校园系统是通过信息化手段,实现对校园内各类资源的有效集成 整合和优化,实现资源的有效配置和充分利用,将校务管理过程的优化协调。为校园提供数字化教学、数字化学习、数字化科研和数字化管理。 致力于为家长和教师提供一个全方位、多层…...

Vue篇.03-组合式API [setup()]
单文件组件(1)<script setup><script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐启用该语法,需要在 <script> 代码块上添加 setup attribute, 里面的代码会被编译成组件 s…...

QHashIterator-官翻
QHashIterator Class template <typename Key, typename T> class QHashIterator QHashIterator 类为 QHash 和 QMultiHash 提供 Java 风格的常量迭代器。更多内容… 头文件:#include qmake:QT core 所有成员列表,包括继承的成员废弃的成员 公共成员函数…...

[qiankun]-部署后线上问题
[qiankun]-部署后线上问题微服务加载问题-现象1现象描述问题分析解决方案微服务加载问题-现象2现象描述问题分析微服务加载问题-现象3现象描述分析解决方案属于项目打包后,部署到服务器上,所遇到的部分问题 微服务加载问题-现象1 现象描述 项目部署实…...

位图数组 布隆过滤器
文章目录位图数组获取索引获取索引状态设置索引状态布隆过滤器特点大致原理位图数组 一个int类型的整数用4字节,也就是32个bit位来表示,将整数类型的数组转换成位图数组,那么存储长度将变为原来的32倍 arr[0] 表示0-31 arr[1] 表示32-63 //...获取索引…...

多线程Thread常用方法和状态
Thread类 及常见方法 1、常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用 Runnable 对象创建线程对象Thread(String name)创建线程对象,并命名Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名Thre…...

Codeforces Round #836 (Div. 2)
A SSeeeeiinngg DDoouubbllee 题意:告诉你一个字符串。若该串上每一位上的字母都可以出现两次,求回文串 思路:正向再反向输出s即可 #include <bits/stdc.h> #define lowbit(x) x&(-x) #define ios cin.sync_with_stdio(false)…...

Python学习之项目实践: 写一个MP3播放器
下面呢,是一个 Python MP3 播放器,它使用 pygame 模块来实现音乐播放功能: import pygame class MP3Player: """ MP3 播放器类 """ def __init__(self): pygame.mixer.init() def play(self, file_path): &quo…...

RocketMQTemplate 实现消息发送
代码托管于gitee:easy-rocketmq 文章目录一、前置工作二、消费者三、生产者1. 普通消息2. 过滤消息3. 同步消息4. 延时消息5. 批量消息6. 异步消息7. 单向消息8. 顺序消息9. 事务消息概要Demo源码解读一、前置工作 1、导入依赖 <dependency><groupId>…...

教师干货丨这5款微课必备提效神器,我要告诉全世界!
微课是一种短小精悍的视频教学形式,其设计和演示因特别简洁明了而被定义为“小而美”。由于只在几分钟时间内向学生传授所需知识,微课为学习者提供更多的选择机会和时间节约的便利,而这种趋势已经逐渐在新的社交媒体环境中显现出来。在制作微…...

timm使用swin-transformer
1.安装 pip install timm2.timm中有多少个预训练模型 #timm中有多少个预训练模型 model_pretrain_list timm.list_models(pretrainedTrue) print(len(model_pretrain_list), model_pretrain_list[:3])3加载swin模型一般准会出错 model_ft timm.create_model(swin_base_pat…...

【java基础】java八大基本数据类型和运算符
文章目录说明八大基本数据类型整型浮点型字符型布尔类型类型转换java运算符基础运算符二元运算符自增自减运算符关系和boolean运算符三元运算符位运算符运算符优先级说明 这里介绍java的八大基本数据类型和运算符 八大基本数据类型 java中有八大数据类型,4个整型…...

Mybatis源码学习笔记(四)之Mybatis执行增删改查方法的流程解析
1 Mybatis流程解析概述 Mybatis框架在执行增伤改的流程基本相同, 很简单,这个大家只要自己写个测试demo跟一下源码,基本就能明白是怎么回事,查询操作略有不同, 这里主要通过查询操作来解析一下整个框架的流程设计实现。 2 Mybat…...

浅谈测试用例设计
前言 最近干的最多的事情就是设计测试用例、评审测试用例了,于是我不禁又想到了一个经典的问题:如何设计出优秀的测试用例? 可能有些童鞋看到这个问题会有些不以为然,这有什么好想的?干个测试谁还不会设计测试用例&a…...

python 利用装饰器实现类似于flask路由
例子1: def f1():print(1111)def f2():print(2222)if __name__ __main__:print(33)打印结果: 33 在例子1中,f1() 与f2() 都没有被调用,只执行了print(33) f1与f2,是没有被调用的,但是如果f1 和 f2 上面…...

git 拉取远程分支到本地
目录:***!本小作者,是将终端和Git的可视化插件结合使用,刚接触的可以自习看一下,内容简单,避免弯路!***一,简单了解远程分支1,连接远程:2,提交&am…...

Answering Multi-Dimensional Range Queries under Local Differential Privacy
文章目录AbstractIntroduction2 PRELIMINARIES2.12.2 Categorical Frequency Oracles4 GRID APPROACHES4.1概述Abstract 在本文中,我们解决了在局部差异隐私下回答多维范围查询的问题。有三个关键的技术挑战:捕捉属性之间的相关性,避免维度的…...

手把手搭建springboot项目05-springboot整合Redis及其业务场景
目录前言一、食用步骤1.1 安装步骤1.1.1 客户端安装1.2 添加依赖1.3 修改配置1.4 项目使用1.5 序列化二、应用场景2.1 缓存2.2.分布式锁2.2.1 redis实现2.2.2 使用Redisson 作为分布式锁2.3 全局ID、计数器、限流2.4 购物车2.5 消息队列 (List)2.6 点赞、签到、打卡 (Set)2.7 筛…...

Flutter基础语法(六)var、final、const、late
Flutter基础 第六章 Flutter关键字var、final、const、late的区别与使用 文章目录Flutter基础前言一、var1.var是什么?2.var如何使用3.var自动推断类型4.var可以再次赋值5.var指定类型二、final1.final是什么?2.final声明但不赋值3.final赋值多次4.final正常使用三、const1.…...

Linux之安装node
Linux之安装node步骤如下 1.去网站下载node 下载地址: https://npm.taobao.org/mirrors/ 2.上传到指定目录下 3.解压 tar -zxvf node-v17.3.0-linux-x644.配置node环境变量 //执行以下命令 vim /etc/profile //在path中加入以下内容 /usr/local/node-v15.14.0/b…...

二叉树、二叉搜索树、二叉树的最近祖先、二叉树的层序遍历【零神基础精讲】
来源0x3f:https://space.bilibili.com/206214 文章目录二叉树[104. 二叉树的最大深度](https://leetcode.cn/problems/maximum-depth-of-binary-tree/)[111. 二叉树的最小深度](https://leetcode.cn/problems/minimum-depth-of-binary-tree/)[129. 求根节点到叶节点…...

【算法】【数组与矩阵模块】求最长可整合子数组和子数组的长度
目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 问题介绍 …...

数据结构:循环队列的实现(leetcode622.设计循环队列)
目录 一.循环队列简单介绍 二.用静态数组实现循环队列 1.数组循环队列结构设计 2.数组循环队列的堆区内存申请接口 3.数据出队和入队的接口实现 4.其他操作接口 5.数组循环队列的实现代码总览 三.静态单向循环链表实现循环队列 1.链表循环队列的结构设计 2.创建静…...

[qiankun]实战问题汇总
[qiankun]实战问题汇总ERROR SyntaxError: Cannot use import statement outside a module问题分析解决方案子应用命名问题问题分析解决方案jsonpFunction详细错误信息问题分析解决方案微应用的注册问题Uncaught Error: application cli5-beta6-test-name died in status LOADI…...

Kafka(6):服务端常用参数配置
参数配置:config/server.properties # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership.…...

2023爱分析·云原生智能运维中台市场厂商评估报告:秒云(miaoyun.io)
目录 1. 研究范围定义 2. 云原生智能运维中台市场定义 3. 厂商评估:秒云(miaoyun.io) 4. 入选证书 1. 研究范围定义 数字化时代,应用成为企业开展各项业务的落脚点。随着业务的快速发展,应用的功能迭代变得越…...

hadoop容器化部署
1、原容器 java:openjdk-8u111-jre jre路径: /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/java-1.8.0-openjdk-amd64 2、安装ssh docker run -it --name hadoop-test java:openjdk-8u111-jre bash apt-get update apt-get install openssh service ssh start …...

【07-JVM面试专题-JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态链接吧?】
JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态链接吧? JVM运行时数据区的虚拟机栈你知道吗?它的基本结构是什么呢?你知道栈帧的结构吗?那你说说动态…...