React 全栈体系(四)

第二章 React面向组件编程

六、组件的生命周期

1. 效果

  • 需求:定义组件实现以下功能:
    • 让指定的文本做显示 / 隐藏的渐变动画
    • 从完全可见,到彻底消失,耗时2S
    • 点击“不活了”按钮从界面中卸载组件

请添加图片描述

<!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 = ()=>{//卸载组件ReactDOM.unmountComponentAtNode(document.getElementById('test'))}//组件挂载完毕componentDidMount(){console.log('componentDidMount');this.timer = setInterval(() => {//获取原状态let {opacity} = this.state//减小0.1opacity -= 0.1if(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>
</body>
</html>

2. 理解

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

3. 生命周期流程图(旧)

请添加图片描述

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

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

  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()

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

  • shouldComponentUpdate()
  • componentWillUpdate()
  • render()
  • componentDidUpdate()

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

  • componentWillUnmount()
<!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">/* 1. 初始化阶段: 由ReactDOM.render()触发---初次渲染1.	constructor()2.	componentWillMount()3.	render()4.	componentDidMount() =====> 常用一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息2. 更新阶段: 由组件内部this.setSate()或父组件render触发1.	shouldComponentUpdate()2.	componentWillUpdate()3.	render() =====> 必须使用的一个4.	componentDidUpdate()3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发1.	componentWillUnmount()  =====> 常用一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息*///创建组件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}//组件将要更新的钩子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>)}}//父组件Aclass 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>)}}//子组件Bclass 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'))</script>
</body>
</html>

4. 生命周期流程图(新)

在这里插入图片描述

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

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

  • constructor()
  • getDerivedStateFromProps
  • render()
  • componentDidMount()

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

  • getDerivedStateFromProps
  • shouldComponentUpdate()
  • render()
  • getSnapshotBeforeUpdate
  • componentDidUpdate()

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

  • componentWillUnmount()
<!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{/* 1. 初始化阶段: 由ReactDOM.render()触发---初次渲染1.	constructor()2.	getDerivedStateFromProps 3.	render()4.	componentDidMount() =====> 常用一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发1.	getDerivedStateFromProps2.	shouldComponentUpdate()3.	render()4.	getSnapshotBeforeUpdate5.	componentDidUpdate()3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发1.	componentWillUnmount()  =====> 常用一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息*///构造器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()}//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromPropsstatic getDerivedStateFromProps(props,state){console.log('getDerivedStateFromProps',props,state);return null}//在更新之前获取快照getSnapshotBeforeUpdate(){console.log('getSnapshotBeforeUpdate');return 'atguigu'}//组件挂载完毕的钩子componentDidMount(){console.log('Count---componentDidMount');}//组件将要卸载的钩子componentWillUnmount(){console.log('Count---componentWillUnmount');}//控制组件更新的“阀门”shouldComponentUpdate(){console.log('Count---shouldComponentUpdate');return true}//组件更新完毕的钩子componentDidUpdate(preProps,preState,snapshotValue){console.log('Count---componentDidUpdate',preProps,preState,snapshotValue);}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>)}}//渲染组件ReactDOM.render(<Count count={199}/>,document.getElementById('test'))</script>
</body>
</html>

请添加图片描述

<!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>

5. 重要的勾子

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

6. 即将废弃的勾子

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

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

七、虚拟DOM与DOM Diffing算法

1. 效果

请添加图片描述

2. 基本原理图

请添加图片描述

3. 代码

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>1_验证diff算法</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 Time extends React.Component {state = {date: new Date()}componentDidMount () {setInterval(() => {this.setState({date: new Date()})}, 1000)}render () {return (<div><h1>hello</h1><input type="text"/><span>现在是:{this.state.date.toTimeString()}<input type="text"/></span></div>)}}ReactDOM.render(<Time/>,document.getElementById('test'))
</script>
</body>
</html>

请添加图片描述
请添加图片描述
请添加图片描述

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>2_key的作用</title>
</head>
<body>
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">/*经典面试题:1). react/vue中的key有什么作用?(key的内部原理是什么?)2). 为什么遍历列表时,key最好不要用index?1. 虚拟DOM中key的作用:1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:(1).若虚拟DOM中内容没变, 直接使用之前的真实DOM(2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOMb. 旧虚拟DOM中未找到与新虚拟DOM相同的key根据数据创建新的真实DOM,随后渲染到到页面2. 用index作为key可能会引发的问题:1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。3. 开发中如何选择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><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>*/class Person extends React.Component{state = {persons:[{id:1,name:'小张',age:18},{id:2,name:'小李',age:19},]}add = ()=>{const {persons} = this.stateconst p = {id:persons.length+1,name:'小王',age:20}this.setState({persons:[p,...persons]})}render(){return (<div><h2>展示人员信息</h2><button onClick={this.add}>添加一个小王</button><h3>使用index(索引值)作为key</h3><ul>{this.state.persons.map((personObj,index)=>{return <li key={index}>{personObj.name}---{personObj.age}<input type="text"/></li>})}</ul><hr/><hr/><h3>使用id(数据的唯一标识)作为key</h3><ul>{this.state.persons.map((personObj)=>{return <li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text"/></li>})}</ul></div>)}}ReactDOM.render(<Person/>,document.getElementById('test'))
</script>
</body>
</html>

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

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

相关文章

特殊矩阵的压缩存储(对称矩阵,三角矩阵和三对角矩阵)

目录 1.对阵矩阵 2.三角矩阵 3.三对角矩阵&#xff08;带状矩阵&#xff09; 均假设数组的下标从0开始 1.对阵矩阵 定义&#xff1a;若对一个n阶矩阵A中的任意一个元素 aᵢ,ⱼ 都有aᵢ,ⱼaⱼ,ᵢ &#xff08;1≤i,j≤n&#xff09;&#xff0c;则称其为对称矩阵。 存储策略…

⛳ MVCC 原理详解

&#x1f38d;目录 ⛳ MVCC 原理详解&#x1f43e; 一、事务回顾&#x1f4d0; 1.1、什么是数据库事务&#xff0c;为什么要有事务&#x1f389; 1.2、事务包括哪几个特性&#xff1f;&#x1f38d; 1.3、事务并发存在的问题1.3.1、脏读1.3.2、不可重复读1.3.3、幻读 &#x1f…

Android Jetpack 中Hilt的使用

Hilt 是 Android 的依赖项注入库&#xff0c;可减少在项目中执行手动依赖项注入的样板代码。执行 手动依赖项注入 要求您手动构造每个类及其依赖项&#xff0c;并借助容器重复使用和管理依赖项。 Hilt 通过为项目中的每个 Android 类提供容器并自动管理其生命周期&#xff0c;…

依赖项的处理与层的创建与注册

依赖项的处理与层的创建与注册 依赖项的处理与层的创建与注册 新问题什么是 layer?layer 的创建与注册 与函数同时创建和绑定单独上传 layer 再绑定函数(推荐) 真正的运行时依赖 注册包的约定与平台强关联的运行时 1. 云端安装依赖2. 本地构建 Amazon Linux 2 容器环境3. 利用…

数字图像滤波的本质

一、说明 在数字时代&#xff0c;图像是我们交流和表达不可或缺的一部分。从社交媒体到医学成像&#xff0c;图像的质量和内容非常重要。这就是图像过滤和卷积领域介入的地方&#xff0c;为我们提供了一个转换和完善这些视觉叙事的工具包。 图像过滤不仅仅是让照片看起来更好;这…

Fiddler 系列教程(二) Composer创建和发送HTTP Request跟手机抓包

Fiddler Composer介绍 Composer的官方帮助文档&#xff1a;http://www.fiddler2.com/fiddler/help/composer.asp Fiddler的作者把HTTP Request发射器取名叫Composer(中文意思是&#xff1a;乐曲的创造者), 很有诗意 Fiddler Composer的功能就是用来创建HTTP Request 然后发送…

Chrome 基于 Wappalyzer 查看网站所用的前端技术栈

1. 找到谷歌商店 https://chrome.google.com/webstore/search/wappalyzer?utm_sourceext_app_menu 2. 搜索 Wappalyzer 3. 添加至Chrome 4. 使用 插件 比如打开 https://www.bilibili.com/ 就可以看到其所以用的前端技术栈了

【系统设计系列】 负载均衡和反向代理

系统设计系列初衷 System Design Primer&#xff1a; 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版&#xff1a; https://github.com/donnemart…

一百七十二、Flume——Flume采集Kafka数据写入HDFS中(亲测有效、附截图)

一、目的 作为日志采集工具Flume&#xff0c;它在项目中最常见的就是采集Kafka中的数据然后写入HDFS或者HBase中&#xff0c;这里就是用flume采集Kafka的数据导入HDFS中 二、各工具版本 &#xff08;一&#xff09;Kafka kafka_2.13-3.0.0.tgz &#xff08;二&#xff09;…

ES 集群常用排查命令

说明&#xff1a;集群使用非默认端口9200&#xff0c;使用的是7116端口举例 一、常用命令 #1.集群健康状态 [wlsadminelastic-01~]$ curl -XGET "http://10.219.27.00:7116/_cluster/health?pretty" { cluster name":"cluster" "status"…

flutter报错-cmdline-tools component is missing

安装完androidsdk和android studio后&#xff0c;打开控制台&#xff0c;出现错误 解决办法 找到自己安装android sdk的位置&#xff0c;然后安装上&#xff0c;并将下面的勾选上 再次运行 flutter doctor 不报错&#xff0c;出现以下画面 Doctor summary (to see all det…

在Git中将本地分支推送到远程仓库

这里很明显 我git云端只有一个master分支 然后 我在本地创建了一个develop分支 然后 现在我想将他放在云端 首先 我们要执行 git checkout -b develop将本地切换到 develop 分支上 因为我这里已经选择的就是了 就不需要了 然后我们执行 git push origin develop这样 刷新云…

队列(Queue)的顶级理解

目录 1.队列(Queue) 的概念 2.单链表模拟实现队列 2.1创建队列 2.2入队列 2.3判断是否为空 2.4出队列 2.5获取队头元素 2.6完整代码&#xff1a; 2.7双向链表模拟实现队列代码 3.数组模拟实现队列代码 3.1创建队列 3.2判断是否为满 3.3检查是否为空 3.4插入元素 3…

静态路由 网络实验

静态路由 网络实验 拓扑图初步配置R1 ip 配置R2 ip 配置R3 ip 配置查看当前的路由表信息查看路由表信息配置静态路由测试 拓扑图 需求&#xff1a;实现 ip 192.168.1.1 到 192.168.2.1 的通信。 初步配置 R1 ip 配置 system-view sysname R1 undo info-center enable # 忽略…

公开游戏、基于有向图的游戏

目录 〇&#xff0c;背景 一&#xff0c;公开游戏、策梅洛定理 1&#xff0c;公开游戏 2&#xff0c;策梅洛定理 二&#xff0c;有向图游戏 1&#xff0c;狭义有向图游戏 2&#xff0c;广义有向图游戏 3&#xff0c;狭义有向图游戏的SG数 4&#xff0c;Bash Game 力扣…

在群晖上安装Nextcloud-AIO详解

本文是应网友 刘源 的要求折腾的&#xff1b; 什么是 Nextcloud AIO &#xff1f; Nextcloud AIO 就是 Nextcloud All-in-One &#xff0c;顾名思义就是一个 Nextcloud 的 All-in-One 版本&#xff0c;这是一个基于 Docker 的项目&#xff0c;它允许仅安装一个容器&#xff0c;…

有哪些适合初学者的编程语言?

C语言 那为什么我还要教你C语言呢&#xff1f;因为我想要让你成为一个更好、更强大的程序员。如果你要变得更好&#xff0c;C语言是一个极佳的选择&#xff0c;其原因有二。首先&#xff0c;C语言缺乏任何现代的安全功能&#xff0c;这意味着你必须更为警惕&#xff0c;时刻了…

【C++进阶】多态

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

如何用Jmeter提取和引用Token

1.执行获取token接口 在结果树这里&#xff0c;使用$符号提取token值。 $根节点&#xff0c;$.data.token表示提取根节点下的data节点下的token节点的值。 2.使用json提取器&#xff0c;提取token 变量路径就是把在结果树提取的路径写上。 3.使用BeanShell取样器或者BeanShell后…