文章目录

  • 一文讲清楚React的render优化,包括shouldComponentUpdate、PureComponent和memo
  • 1. React的渲染render机制
  • 2. shouldComponentUpdate
    • 2.1 先上单组件渲染,验证state变化
    • 2.2 上父子组件,验证props
  • 2. PureComponent
    • 2.1 单组件验证state
    • 2.2 父子组件验证props
  • 3.React.memo
  • 4. 总结

一文讲清楚React的render优化,包括shouldComponentUpdate、PureComponent和memo

1. React的渲染render机制

  • 我们都知道,在React中,state和props的改变以及父组件人render执行都会造成render的重新执行
  • 关于这点不懂的,看这篇文章一文讲清楚React中的render机制
  • 但是在某些复杂的业务场景下,如果大量的子组件在没有发生任何变化的情况下被更新,就会造成一定的性能影响
  • 我们希望的是,只有在子组件state和props有变化,且判定为需要重新渲染的情况下再执行render进行渲染
  • 能不能做到呢,恭喜,还真能做到
  • 我们可以通过三驾马车,shouldComponentUpdate、PureComponent、memo来实现

2. shouldComponentUpdate

  • 见名知意,组件应不应该更新,所以这里应该有一个条件判断,如果返回true,则更新,如果返回false,则不更新
  • 判断什么呢,判断state和props是否发生变化,如果变化了,说明页面需要重新渲染,那我们就是返回true,反之亦然
  • 话不多说,上代码

2.1 先上单组件渲染,验证state变化

import React from 'react'
class App extends React.Component{constructor(props){super(props)this.state={num:0}}handleClick=()=>{this.setState({num:0})}render(){console.log('render() has been executed')return(<div><div>{this.state.num}</div><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 我们首次运行后发现,render() has been executed被打印了一次,说明render执行了一次,这是正常的,首席渲染
  • 然后我们点击button,发现render() has been executed又被打印了一次,说明render又执行了一次渲染,但是我们在button里面没有改变state的状态,num还是0,render理论上不执行才是最好的选择
  • 这时候shouldComponentUpdate就派上用场了
  • 我们只要在shouldComponentUpdate里面判断state是否发生了变化,如果没有,返回false,这样render就不会执行了
  • 上代码
import React from 'react'
class App extends React.Component{constructor(props){super(props)this.state={num:0}}shouldComponentUpdate(nextProps,nextState,nextContent){//nextProps表示即将接受的新的props//nextState表示即将接受的心得State,//这里我们通过判断nextState.num === this.state.num,如果是返回false,阻止render执行;如果true,render继续渲染if(nextState.num ===  this.state.num){return false }else{return true}}handleClick=()=>{this.setState({num:0})}render(){console.log('render() has been executed')return(<div><div>{this.state.num}</div><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 这时候我们再运行,首次还是会打印render() has been executed,说明render首次渲染,这是正常的情况
  • 然后我们点击button,发现render() has been executed没有再被打印,说明我们通过shouldComponentUpdate已经阻止了本次render渲染,应为状态没有发生变化
  • 这时候我们改变一下handleClick方式,让发state状态发生变化,看render会不会执行
import React from 'react'
class App extends React.Component{constructor(props){super(props)this.state={num:0}}shouldComponentUpdate(nextProps,nextState,nextContent){//nextProps表示即将接受的新的props//nextState表示即将接受的心得State,//这里我们通过判断nextState.num === this.state.num,如果是返回false,阻止render执行;如果true,render继续渲染if(nextState.num ===  this.state.num){return false }else{return true}}handleClick=()=>{this.setState({num:this.state.num+1})}render(){console.log('render() has been executed')return(<div><div>{this.state.num}</div><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 运行,点击button发现打印render() has been executed,说明render执行渲染了,因为state发生变化了
  • 如此,shouldComponentUpdate逻辑验证完毕

2.2 上父子组件,验证props

  • 直接上代码
import React from 'react'
//定义子组件
class Child extends React.Component{constructor(props){super(props)}render(){console.log(' Child render() has been executed')return (<div>childNum :{this.props.childNum}</div>)}
}
class App extends React.Component{constructor(props){super(props)this.state={num:0,childNum:0}}   handleClick=()=>{this.setState({num:this.state.num+1})}render(){return(<div><div>num :{this.state.num}</div><Child childNum={this.state.childNum}></Child><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 我们运行,首次子组件render会执行,打印Child render() has been executed
    在这里插入图片描述

  • 然后我们点击父组件的button给num自增1,这时候父组件因为state发生变化了,要执行 render,但是传递给子组件的props并没有发生变化,我们没有对ChildNum做任何处理

  • 但是我们会发现,点击button的时候打印了Child render() has been executed,说明子组件的render执行了,子组件被重新渲染了,这不是我们想要的

  • 我们希望props不发生变化的时候,子组件不执行render,这首shouldComponentUpdate该上场了

import React from 'react'
//定义子组件
class Child extends React.Component{constructor(props){super(props)}shouldComponentUpdate(nextProps,nextState,nextContext){//nextProps表示即将接受的新的props//nextState表示即将接受的心得State,//这里我们通过判断nextState.num === this.state.num,如果是返回false,阻止render执行;如果true,render继续渲染if(nextProps.childNum === this.props.childNum){return false}else{return true}}render(){console.log(' Child render() has been executed')return (<div>childNum :{this.props.childNum}</div>)}
}
class App extends React.Component{constructor(props){super(props)this.state={num:0,childNum:0}}   handleClick=()=>{this.setState({num:this.state.num+1})}render(){return(<div><div>num :{this.state.num}</div><Child childNum={this.state.childNum}></Child><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 我们再运行,点击button,发现子组件的render方法并没有执行,因为props没有发生变化
  • 这时候我们改变一下父组件的handleClick方法,让childNum也变化一下,看子组件render会不会执行
import React from 'react'
//定义子组件
class Child extends React.Component{constructor(props){super(props)}shouldComponentUpdate(nextProps,nextState,nextContext){//nextProps表示即将接受的新的props//nextState表示即将接受的心得State,//这里我们通过判断nextState.num === this.state.num,如果是返回false,阻止render执行;如果true,render继续渲染if(nextProps.childNum === this.props.childNum){return false}else{return true}}render(){console.log(' Child render() has been executed')return (<div>childNum :{this.props.childNum}</div>)}
}
class App extends React.Component{constructor(props){super(props)this.state={num:0,childNum:0}}   handleClick=()=>{this.setState({num:this.state.num+1,childNum:this.state.childNum+1//让子组件的props也发生变化})}render(){return(<div><div>num :{this.state.num}</div><Child childNum={this.state.childNum}></Child><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 运行,点击button,发现子组件的render又被执行了,完美,props验证完毕

2. PureComponent

2.1 单组件验证state

  • 上面我们通过在shouldComponent先state和props的判断逻辑,决定要不要执行render,这样的问题在于每次都要写,就比较麻烦,如果React能提供一套内置的比较逻辑,这样我们就不用每次写了,有没有这样的功能呢,有,那就是PureComponent
  • PureComponent通过浅比较props和state自动实现shouldComponentUpdate,从而决定render是否执行,他是React.Component的一个变体,我们直接实现继承就可以实现
  • 浅比较比较好理解吧,不懂的自行研究一下,因为是浅比较,所以PureComponent适合一下数据结构简单扁平的基本类型
  • 话不多说上代码
import React from 'react'
class App extends React.PureComponent{constructor(props){super(props)this.state={num:0}}handleClick=()=>{this.setState({num:0})}render(){console.log('render() has been executed')return(<div><div>{this.state.num}</div><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 运行,点击button,发现render不行执行,
  • 改变handleClick,再次验证
import React from 'react'
class App extends React.PureComponent{constructor(props){super(props)this.state={num:0}}handleClick=()=>{this.setState({num:this.state.num+1})}render(){console.log('render() has been executed')return(<div><div>{this.state.num}</div><button onClick={this.handleClick}>button</button></div>)}
}
export default App
  • 运行点击button,发现render被执行,验证完毕

2.2 父子组件验证props

  • 类比结合1.2和2.1,小伙伴们资兴市实现以下,不会的留言解答

3.React.memo

  • 上面我们讨论的都是类组件的state和props的变化产生的render性能优化
  • 针对函数组件,React提出了memo
  • memo的作用可以理解为只比较props的PureComponent,因为函数组件没有状态么
  • 上代码
import React from 'react'
const Child=function Child(props){console.log('child function has been executed')return (<div>num from props:{props.num}</div>)
}
function App(props){const [num,setNum]=React.useState(0)const [count,setCount]=React.useState(0)return(<div><div>count:{count}</div><Child num={num}></Child><button onClick={()=>{setCount(count=>count+1)}}>button</button></div>)
}
export default App
  • 运行,首次渲染子组件,打印child function has been executed
  • 点击button,打印child function has been executed,说明子组件又被重新渲染了,是因为虽然num的值没有变化,但是count的值改变导致父组件重新渲染,进一步导致子组件重新渲染
  • 这时候我们加个React.memo,让props不发生变化的情况下,子组件不被重新渲染
import React from 'react'
const Child=React.memo(function Child(props){console.log('child function has been executed')return (<div>num from props:{props.num}</div>)
})
function App(props){const [num,setNum]=React.useState(0)const [count,setCount]=React.useState(0)return(<div><div>count:{count}</div><Child num={num}></Child><button onClick={()=>{setCount(count=>count+1)}}>button</button></div>)
}
export default App
  • 运行,点击button,不打印,子组件不重新渲染
  • 然后改变父组件的num,让num也变化起来,看看子组件渲染情况
import React from 'react'
const Child=React.memo(function Child(props){console.log('child function has been executed')return (<div>num from props:{props.num}</div>)
})
function App(props){const [num,setNum]=React.useState(0)const [count,setCount]=React.useState(0)return(<div><div>count:{count}</div><Child num={num}></Child><button onClick={()=>{setCount(count=>count+1);setNum(num=>num+1)}}>button</button></div>)
}
export default App
  • 运行,点击button,子组件重新被渲染,验证完毕

4. 总结

  • 根据不同的业务场景和数据结构,选用不同的render性能优化方式

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

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

相关文章

物联网iot、mqtt协议与华为云平台的综合实践(万字0基础保姆级教程)

本学期的物联网技术与应用课程&#xff0c;其结课设计内容包含&#xff1a;mqtt、华为云、PyQT5和MySQL等结合使用&#xff0c;完成了从华为云配置产品信息以及转发规则&#xff0c;到mqtt命令转发&#xff0c;再到python编写逻辑代码实现相关功能&#xff0c;最后用PyQT5实现面…

使用IntelliJ IDEA和Maven搭建SpringBoot集成Fastjson项目

使用IntelliJ IDEA和Maven搭建SpringBoot集成Fastjson项目 下面我将详细介绍如何在IntelliJ IDEA中使用Maven搭建一个集成Fastjson的SpringBoot项目&#xff0c;包含完整的环境配置和代码实现。 一、环境准备 软件要求 IntelliJ IDEA 2021.x或更高版本JDK 1.8或更高版本&#x…

Java从入门到精通!第九天, 重点!(集合(一))

十一、集合1. 为什么要使用集合(1) 数组存在的弊端1) 数组在初始化之后&#xff0c;长度就不能改变&#xff0c;不方便扩展。2) 数组中提供的属性和方法比较少&#xff0c;不便于进行添加、删除、修改等操作&#xff0c;并且效率不高&#xff0c;同时无法直接存储元素的个数。3…

为什么使用时序数据库

为什么使用时序数据库&#xff1f; 时序数据库&#xff08;Time-Series Database, TSDB&#xff09;是专为时间序列数据优化的数据库&#xff0c;相比传统关系型数据库&#xff08;如MySQL&#xff09;或NoSQL数据库&#xff08;如MongoDB&#xff09;&#xff0c;它在以下方面…

计算机网络:(十一)多协议标记交换 MPLS

计算机网络&#xff1a;&#xff08;十一&#xff09;多协议标记交换 MPLS前言一、传统网络的问题二、MPLS&#xff1a;给数据包贴个“标签”三、MPLS的工作流程1. 入站2. 中间3. 出站四、MPLS的能力前言 前面我们讲解了计算机网络中网络层的相关知识&#xff0c;包括网络层转发…

docker run elasticsearch 报错

谷粒商城 p103 前提条件&#xff1a; 下载镜像文件 #存储和检索数据 docker pull elasticsearch:7.4.2 #可视化检索数据 docker pull kibana:7.4.2 创建挂载的文件和配置 mkdir -p /mydata/elasticsearch/config mkdir -p /mydata/elasticsearch/data echo "http.h…

巧用Callbre RVE生成DRC HTML report及CTO的使用方法

对于后端版图人员&#xff0c;在芯片TO前的LV signoff阶段&#xff0c;犹如一段漫长而有期待的朝圣之旅&#xff0c;需要耐心&#xff0c;毅力和信心&#xff0c;在庞杂的DRC中找到一条收敛之路。为了让此路更为清晰收敛&#xff0c;Calibre提供了一套可追溯对比的富文本方式-H…

产品需求文档(PRD)格式全解析:从 RP 到 Word 的选择与实践

产品需求文档&#xff08;PRD&#xff09;的形式多种多样&#xff0c;但核心目标始终一致&#xff1a;清晰传递产品需求&#xff0c;让团队高效协作。不同公司对 PRD 的格式要求可能不同&#xff0c;有的偏爱直接在原型工具中撰写&#xff0c;有的则习惯用 Word 整理归档。本文…

【C++】入门阶段

一、初始化C中的初始化指为变量赋予初始值的过程。初始化方式多样&#xff0c;适用于不同场景。char cha0; char chb{0}; char chc(\0); char chdcha; char che{};注意事项优先使用列表初始化&#xff08;{}&#xff09;&#xff0c;避免窄化转换风险。在c11中{ }在变量&#x…

tailscale在ubuntu22.04上使用

支持 x86 和 ARM 架构 CPU 的软件包已提供 32 位和 64 位版本。 添加 Tailscale 的软件包签名密钥及仓库&#xff1a; curl -fsSL https://pkgs.tailscale.com/stable/ubuntu/noble.noarmor.gpg | sudo tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null c…

深入解析Linux文件重定向原理与dup2系统调用

在Linux中&#xff0c;重定向&#xff08;Redirection&#xff09;是一种强大的功能&#xff0c;允许用户控制命令的输入来源&#xff08;stdin&#xff09;和输出目标&#xff08;stdout和stderr&#xff09;。通过重定向&#xff0c;你可以将命令的输出保存到文件、从文件读取…

QGIS制作的仪表盘工程

在QGIS的官方资源库下载了一个QGIS制作的仪表盘工程&#xff0c;感觉非常炫酷&#xff01;分享给大家&#xff01;下面的仪表盘会将选中的道路数及长度&#xff0c;动态显示在相应的仪表项中&#xff01;下面的仪表盘会将选中的道路数及长度&#xff0c;动态显示在相应的仪表项…

Python高级数据类型:集合(Set)

集合是Python中一种非常有用的数据结构&#xff0c;它与列表类似但具有独特的特性。本文将全面介绍集合的所有知识点&#xff0c;从基础概念到高级用法&#xff0c;帮助初学者彻底掌握集合的使用。1. 集合简介1.1 什么是集合&#xff1f;集合&#xff08;Set&#xff09;是Pyth…

【Unity编辑器开发GUI.Window】

Unity GUI.Window 笔记 根据官方文档2021版本的&#xff0c;点击链接跳转记录 概述 GUI.Window 是 Unity IMGUI 系统中用于创建弹出窗口的核心方法&#xff0c;具有以下关键特性&#xff1a; 浮动窗口&#xff1a;浮于普通 GUI 控件之上焦点控制&#xff1a;可通过点击获得焦…

CAN通信驱动开发注意事项

以下是CAN通信驱动开发的关键注意事项相关的整理,涵盖硬件配置、协议实现、错误处理及性能优化等方面: 一、硬件层配置要点 引脚复用与时钟 确认MCU的CAN控制器引脚是否与GPIO复用,正确配置复用模式。 检查CAN控制器时钟源,确保波特率计算基准准确。 收发器(Transceiver)…

CCF编程能力等级认证GESP—C++8级—20250628

CCF编程能力等级认证GESP—C8级—20250628单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)树上旅行遍历计数单选题&#xff08;每题 2 分&#xff0c;共 30…

135. Java 泛型 - 无界通配符

文章目录135. Java 泛型 - 无界通配符 (?)**1. 什么是无界通配符 (?)&#xff1f;****2. 为什么使用无界通配符&#xff1f;****3. 示例&#xff1a;使用 ? 处理任意列表****❌ 错误示例****✅ 正确示例****4. 为什么 List<Object> 和 List<?> 不一样&#xff…

NOIP提高组|2010T1机器翻译

NOIP2010年提高组第一题:机器翻译 题目描述 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章。 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义来替换。对于每个英文单词,软件会先在内存中查找这个单词的中文含义,如果…

Change Data Capture (CDC) with Kafka Connect:实时数据同步的完整指南

Change Data Capture (CDC) 是一种高效的数据同步技术&#xff0c;能够捕获数据库的变更&#xff08;插入、更新、删除&#xff09;并实时传输到其他系统。结合 Kafka Connect&#xff0c;我们可以构建一个可靠、可扩展的 CDC 管道&#xff0c;实现数据库与数据湖、数据仓库或消…

云手机网络加速全攻略:解决游戏卡顿与APP连接失败困扰

用云手机玩游戏、挂脚本、跑自动任务&#xff0c;明明后台显示在线&#xff0c;但画面卡顿、操作延迟、甚至APP直接“转圈圈连不上”&#xff0c;是不是很抓狂&#xff1f;问题出在哪里&#xff1f;云手机不卡&#xff0c;网络卡&#xff1f;其实&#xff0c;大多数云手机的性能…