位置: IT常识 - 正文

React避免组件重复渲染(react避免子组件更新)

编辑:rootadmin
##前言 在 React 开发中如果不去管组件的重复渲染问题,项目稍微复杂一点性能将不堪入目,下面将介绍项目中最常见的例子及解决方案(仅 hooks 组件)。 ##预先了解所用知识 React.memo React.useCallback React.useMemo useMemoizedFn(利用 ... 前言

推荐整理分享React避免组件重复渲染(react避免子组件更新),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:react 组件销毁,react 组件销毁,react 组件销毁,react组件必不可少的函数,React避免组件重渲染,react组件重新加载,React避免组件重渲染,react避免子组件更新,内容如对您有帮助,希望把文章链接给更多的朋友!

在 React 开发中如果不去管组件的重复渲染问题,项目稍微复杂一点性能将不堪入目,下面将介绍项目中最常见的例子及解决方案(仅 hooks 组件)。

预先了解所用知识React.memoReact.useCallbackReact.useMemouseMemoizedFn(利用 ref + useMemo 配合单例模式实现比 useCallback 更加好用的 hook,下面会提,强烈推荐)

没错,只需使用上面4点即可解决大多数组件重复渲染问题,而如何合理去使用呢?

例1: 父组件状态更新导致子组件无效渲染const Parent = () => { const [count, setCount] = useState(0); const [son1Count, setSon1Count] = useState(0); const [son2Count, setSon2Count] = useState(0); return ( <div> {console.log("Parent render")} <button onClick={() => setCount(v => v + 1)}>Parent + 1</button> <button onClick={() => setSon1Count(v => v + 1)}>Son1 + 1</button> <button onClick={() => setSon2Count(v => v + 1)}>Son2 + 1</button> <h3>Parent: {count}</h3> <Son1 son1Count={son1Count} /> <Son2 son2Count={son2Count} /> </div> );};const Son1 = (props) => { return ( <div> {console.log("Son1 render")} Son1: {props.son1Count} </div> );};const Son2 = (props) => { return ( <div> {console.log("Son2 render")} Son2: {props.son2Count} </div> );};

可以看出,无论改变哪个值,所有组件都重新渲染了,理想情况是改变 count 值实际并不需要 Son1 和 Son2 组件重新渲染,改变 son1Count 也不需要 Son2 重新渲染,简而言之就是子组件所依赖的值没发生变化就不需要重新渲染,上面情况只需将子组件用 React.memo 包裹即可:

const Son1 = React.memo((props) => { return ( <div> {console.log("Son1 render")} Son1: {props.son1Count} </div> );});const Son2 = React.memo((props) => { return ( <div> {console.log("Son2 render")} Son2: {props.son2Count} </div> );});React避免组件重复渲染(react避免子组件更新)

可以看到轻松包裹一下就已经达到理想效果,React.memo 本质就是一个高阶组件(HOC),通过浅比较(比较栈内存中的值) props、state 和 render 的内容来判断是否需要重新渲染组件。而有时候子组件不得不依赖父组件的值,但这个依赖的值发生改变又不需要重新渲染组件怎么办,接着看下面例2。

例2: 自定义子组件是否重新渲染const Parent = () => { const [random, setRandom] = useState(Math.random()); const [nowTime, setNowTime] = useState(new Date().toLocaleString()); const timerRef = useRef(); useEffect(() => { timerRef.current = setInterval(() => { setRandom(Math.random()); }, 1000); return () => { clearInterval(timerRef.current); }; }); return ( <div> {console.log("Parent render")} <h3>random: {random}</h3> <button onClick={() => setNowTime(new Date().toLocaleString())}> 点击更新子组件 </button> <Son random={random} nowTime={nowTime} /> </div> );};const Son = React.memo( (props) => { return ( <div> {console.log("Son render")} <p> {props.nowTime}父组件 random 值为: {props.random} </p> </div> ); });

上面例子中,子组件依赖父组件 random 和 nowTime,而子组件理想是在点击按钮 nowTime 发生改变后 才重新渲染组件显示 random 的值,不需要上面那样实时渲染,此时只需要在 React.memo 第二个参数自定义渲染规则即可,React.memo 第二个参数为可选参数:

function memo<P extends object>( Component: FunctionComponent<P>, propsAreEqual?: (prevProps: Readonly<PropsWithChildren<P>>, nextProps: Readonly<PropsWithChildren<P>>) => boolean): NamedExoticComponent<P>;

看函数签名可知,第二个参数可传一个回调函数,回调函数会有两个形参,props 状态改变前的值和改变后的值,返回值为一个布尔值,true 禁止重新渲染,false 将重新渲染,和以往 class 组件中的 shouldComponentUpdate 生命周期钩子用法很像,下面加入自定义渲染判断条件,即只在 props.nowTime 发生改变时进行重新渲染:

const Son = React.memo( (props) => { return ( <div> {console.log("Son render")} <p> {props.nowTime}父组件 random 值为: {props.random} </p> </div> ); }, (prevProps, nextProps) => prevProps.nowTime === nextProps.nowTime);

从上图可见只有 props.nowTime 发生改变才会重新渲染。第二个参数的判断规则在实际开发中还有很多妙用,比如一些情况可以替代 useCallback,后面会提一下。

例3: 向子组件传递方法(状态提升)导致子组件无效渲染const Parent = () => { const [count, setCount] = useState(0); const [sonCount, setSonCount] = useState(0); const allPlus = () => { setCount(v => v + 1); setSonCount(v => v + 1); }; return ( <div> {console.log("Parent render")} <button onClick={() => setCount(v => v + 1)}>Parent + 1</button> <h3>Parent: {count}</h3> <Son allPlus={allPlus} sonCount={sonCount} /> </div> );};const Son = React.memo((props) => { return ( <div> {console.log("Son render")} <p>Son: {props.sonCount}</p> <button onClick={props.allPlus}>All + 1</button> </div> );});

从控制台输出可以看见,当传递一个方法给子组件时,就算使用 React.memo 进行包裹也不济于事,导致该问题出现的根本原因是当 count 发生改变导致父组件发生重新渲染,Parent 组件本质也是一个函数,所以 const allPlus = () => { setCount(count + 1); setSonCount(sonCount + 1); }; 也会重新执行一次,这就意味着 allPlus 已经重新赋值,此时虽然看起来没什么变化,实际上 allPlus 在栈内存中的地址已经改变,而 React.memo 默认正是通过浅比较决定是否重新渲染,也就导致只要父组件发生重绘,子组件一定会跟着无效重绘。使用 React.useCallback 缓存函数解决子组件无效渲染,只需将上面 allPlus 方法使用 useCallback 包裹:

const allPlus = useCallback(() => { setCount(v => v + 1); setSonCount(v => v + 1); }, []);

function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;

从 useCallback 函数签名看到,需要传递两个参数,第一个传需要缓存的函数,第二个是依赖值,其本质就是返回的是一个 memoized(缓存)函数,在依赖不变的情况下,多次定义的时候,返回的值是相同的,他的实现原理是当使用一组参数初次调用函数时,会缓存参数和计算结果,当再次使用相同的参数调用该函数时,会直接返回相应的缓存结果,上面例子依赖值为空数组,所以无论怎样 allPlus 栈内存值都不会变,也就不会触发子组件无效重绘。在向子组件传递方法时在项目中很多时候会懒得专门

本文链接地址:https://www.jiuchutong.com/zhishi/304635.html 转载请保留说明!

上一篇:织梦DEDECMS栏目后台设置隐藏,前台栏目如何显示(织梦如何给栏目增加缩略图)

下一篇:python中datetime和字符串之间如何转换(python中datetime用法)

  • 石头机器人怎么重新连wifi(石头机器人怎么充电)

    石头机器人怎么重新连wifi(石头机器人怎么充电)

  • 小米出现fastboot怎么开机(小米出现fastboot开不了机一直循环)

    小米出现fastboot怎么开机(小米出现fastboot开不了机一直循环)

  • vivox70怎么设置返回键(vivox70怎么设置定时开关机)

    vivox70怎么设置返回键(vivox70怎么设置定时开关机)

  • 三星s10+是双卡双待吗(三星s10是双卡双待怎么放卡)

    三星s10+是双卡双待吗(三星s10是双卡双待怎么放卡)

  • 爱思加强版可以删除吗(爱思加强版可以更新软件吗)

    爱思加强版可以删除吗(爱思加强版可以更新软件吗)

  • 微信文件没下载过期了怎么恢复(微信文件没下载过期了苹果)

    微信文件没下载过期了怎么恢复(微信文件没下载过期了苹果)

  • 钉钉普通群和内部群的区别(钉钉群内部群和普通群的区别)

    钉钉普通群和内部群的区别(钉钉群内部群和普通群的区别)

  • 快手退货商家一直拒绝(快手退货商家一直说没收到货怎么办)

    快手退货商家一直拒绝(快手退货商家一直说没收到货怎么办)

  • ipad卡在白苹果界面(ipad卡在白苹果怎么办)

    ipad卡在白苹果界面(ipad卡在白苹果怎么办)

  • 华为p40充满电要多久(华为p40充满电要2小时)

    华为p40充满电要多久(华为p40充满电要2小时)

  • sim卡可能被植入病毒吗(sim卡可能被植入监听)

    sim卡可能被植入病毒吗(sim卡可能被植入监听)

  • 头条审核慢是什么原因(头条审核好几天)

    头条审核慢是什么原因(头条审核好几天)

  • matlab怎么调用函数(matlab怎么样调用函数)

    matlab怎么调用函数(matlab怎么样调用函数)

  • 苹果笔记本需要贴膜吗(苹果笔记本需要清灰吗)

    苹果笔记本需要贴膜吗(苹果笔记本需要清灰吗)

  • 芒果tv赠送影片的方法(芒果tv赠片有限制)

    芒果tv赠送影片的方法(芒果tv赠片有限制)

  • nova6se怎么截屏(nova6se怎么截长图)

    nova6se怎么截屏(nova6se怎么截长图)

  • 有没有抖音钻卡(抖音钻石卡抖音怎么得)

    有没有抖音钻卡(抖音钻石卡抖音怎么得)

  • 淘宝店铺销量怎么计算(淘宝店铺销量怎么做)

    淘宝店铺销量怎么计算(淘宝店铺销量怎么做)

  • vivox27参数(vivox27参数配置详情 参数设置)

    vivox27参数(vivox27参数配置详情 参数设置)

  • 华为mate30双卡怎么插(华为mate30双卡怎么插卡)

    华为mate30双卡怎么插(华为mate30双卡怎么插卡)

  • 爱普生打印机怎么连接电脑(爱普生打印机怎么安装)

    爱普生打印机怎么连接电脑(爱普生打印机怎么安装)

  • iphone11可以双卡双待吗(iphone11可以双卡双待怎么插卡)

    iphone11可以双卡双待吗(iphone11可以双卡双待怎么插卡)

  • 电脑行间距在哪里设置(电脑行间距在哪找)

    电脑行间距在哪里设置(电脑行间距在哪找)

  • 天猫精灵有什么用(天猫精灵有什么游戏可以玩)

    天猫精灵有什么用(天猫精灵有什么游戏可以玩)

  • 如何制作ps视频(怎么制作ps视频)

    如何制作ps视频(怎么制作ps视频)

  • 微信封号后好友知道吗(微信封号后好友辅助怎么弄)

    微信封号后好友知道吗(微信封号后好友辅助怎么弄)

  • 怎么把酷狗音乐下载到u盘(怎么把酷狗音乐下载到文件夹)

    怎么把酷狗音乐下载到u盘(怎么把酷狗音乐下载到文件夹)

  • 如果网页上有错误该如何解决呢?(如果网页上有错字怎么办)

    如果网页上有错误该如何解决呢?(如果网页上有错字怎么办)

  • 苹果发布macOS 11 Big Sur 第二个公测版(附更新内容)(苹果发布macOS13.6)

    苹果发布macOS 11 Big Sur 第二个公测版(附更新内容)(苹果发布macOS13.6)

  • 装卸费属于什么费用
  • 公司取得违约金合法吗
  • 实收资本实务处理办法
  • 工程设备公司经营范围
  • 预付账款和应付账款的区别
  • 电信没有基站为什么信号也很好
  • 免租期房租怎么做会计分录
  • 发票税号不对还能报销吗
  • 进口增值税的计税依据
  • 增资款怎么做账
  • 物业公司收取供热管道内网的维护费用合理吗
  • 基本户收到零余额转款怎么做分录
  • 质量问题扣款账务处理
  • 企业每个月都要关账吗
  • 印花税一定要贴花吗
  • 地税附加税减免政策
  • 联营与参股公司的关系
  • 小规模纳税人免征增值税怎么记账
  • 垫付按揭保证金怎么做账
  • 生产设备软件服务有哪些
  • 所得税费用属于损失吗
  • 厂房转让会计分录
  • 启动器
  • 收到工会经费怎样做账
  • 航空公司收取什么费
  • 资产处置收益与固定资产清理
  • 企业工会会费是什么意思
  • 电脑开机时出现用户账户控制提示
  • 编制竣工决算的主要依据
  • 工商年检需准备什么资料
  • vue 页面生成pdf
  • php的json_encode
  • npm ERR! notarget No matching version found for xxx@^1.0.64. npm 插件安装失败
  • react 入门
  • 新开企业如何在电子税务局操作
  • 财政拨入的科技费是什么
  • mysql5.7.35安装配置教程
  • php和mysql的联合使用解决了
  • mysql执行时间太长
  • mongodb的redo日志为
  • phpcms添加内容
  • 工程施工与工程结算对冲分录
  • 财政拨款结余明细科目编码
  • 即征即退进项划分说明
  • SQL一条语句统计记录总数及各状态数
  • 工会经费与残保金属于什么
  • 国库券利息收入属于企业所得税纳税调整项目
  • 解除劳动合同经济补偿金法律依据
  • 购买固定资产记账
  • 房地产成本的概念
  • 支付借款利息需要交税吗
  • 按预测范围不同划分为以下几类
  • 企业购买土地如何缴税
  • 防伪税控技术维护费
  • 新冠肺炎疫情相关的公共政策
  • 会计调账情况模板
  • 公司注销固定资产清理怎么做账务处理
  • 建账有哪些步骤,每个步骤有哪些注意事项
  • mysql中计算两个日期之间的天数
  • centos下安装jdk
  • win7隐藏共享文件夹
  • 单网卡计算机有几个网络接口
  • 黑苹果驱动说明
  • linux 去除换行
  • linux useradd -m
  • js 读取 excel
  • node.js安装教程详细
  • 最新推荐美剧
  • [置顶]JM259194
  • python字符串怎么用
  • putty自动退出
  • [置顶]JM259194
  • Android使用opencv处理图片灰度
  • 编写python代码
  • 如何彻底删除android
  • 税收预测的内容
  • 增值税已申报但是忘清卡
  • 建筑行业增值税税收优惠政策
  • 金三系统企业所得税如何变更所得税缴纳方式?
  • 医保电子凭证怎么激活
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设