正确使用React组件缓存
简介
正常来讲的话当我们点击组件的时候,该组件以及该组件的子组件都会重新渲染,但是如何避免子组件重新渲染呢,我们经常用memo来解决
React.memo配合useCallback缓存组件
- 父组件没有传props
const Index = ()=> {console.log('子组件刷新了');return (<div>这是子组件</div>)
}
//这里我们用react.memo对组件进行包裹,包裹一次之后react在render的过程中不会给该fiber打上更新的tag
//从而跳过更新,这个原理其实就是react.memo的第二个参数上,如果react.memo第二个参数不传递,react回默
//认给我们补充上第二个参数的逻辑,其中逻辑就是浅比较Index组件的props参数,如果相等的话默认第二个参数返
//回true,组件就会缓存了,如果不相等的话就会返回false组件就会重新打上更新的tag然后重新渲染。
const MemoIndex = React.memo(Index);const App = ()=>{const [state, setState] = useState(0);return (<div className="App"><button onClick={()=>setState(state+1)}>点我看看子组件刷新了吗</button><MemoIndex/></div>);
}
- 父组件传了state
const Index = ()=> {console.log('子组件刷新了');return (<div>这是子组件</div>)
}
//其实这Index组件不会更新的,react检测到我们不传递第二个参数的话,会把之前的props拆出来,和现在的
//props做比较 发现pre.next === cur.next 然后回返回true组件就会缓存了
const MemoIndex = React.memo(Index);
//这行代码就相当这样的代码
const MemoIndex = React.memo(Index, (pre, cur)=> {//这样写的就比较简单了,因为这是是针对于当前的demo来说的。react比较的代码逻辑比较复杂,因为react//需要考虑到多种情况,props中参数可能多一个少一个的情况,所以react默认提供的代码比较复杂if(pre.name === cur.name) {return true;}return false;
});const App = ()=>{const [state, setState] = useState(0);return (<div className="App"><button onClick={()=>setState(state+1)}>点我看看子组件刷新了吗</button><MemoIndex name={0}/></div>);
}
- 父组件传了函数
const Index = ()=> {console.log('子组件刷新了');return (<div>这是子组件</div>)
}
const MemoIndex = React.memo(Index);const App = ()=>{const [state, setState] = useState(0);const func = ()=> {};return (<div className="App">//这时候子组件会不会刷新呢,有的同学可能说不会因为浅比较发现pre.func === cur.func 返回//true所以不会刷新,但是其实是会刷新的,因为APP组件中触发了setState之后App组件重新渲染,也//就是相当于执行了App()这个方法,所以里面func的指向地址发生了变化,所以pre.func !== //cur.func 子组件会重新渲染,<button onClick={()=>setState(state+1)}>点我看看子组件刷新了吗</button><MemoIndex func={func}/></div>);
}
使用useCallback缓存函数
const Index = ()=> {console.log('子组件刷新了');return (<div>这是子组件</div>)
}const MemoIndex = React.memo(Index);const App = ()=>{const [state, setState] = useState(0);//这里我们用了useCallback,useCallback主要是缓存我们当前的函数,如果我们第二个参数传递空数组的话//他的地址不会改变,如果我们第二个参数传递的是一个变量,这个变量发生变化他的地址就会发生变化。所以这//和useEffect的第二个参数是一样的,但是请注意不要滥用useCallback的第二个参数。如果第二个参数滥用//会拿到我们之前的值。我们看下一个示例就知道了const func = useCallback(()=> {}, [])return (<div className="App"><button onClick={()=>setState(state+1)}>点我看看子组件刷新了吗</button><MemoIndex func={func}/></div>);
}
使用useMemo缓存组件
useMemo不仅可以缓存变量,函数还可以缓存组件
const Index = (props)=> {console.log('子组件刷新了');return (<div>这是子组件</div>)
}const App = ()=>{const [state, setState] = useState(0);//使用useMemo也要和useCallback一样特别注意第二个参数,因为他有可能导致我们拿不到最新的数据解决//解决方案就和useCallback的一样,简单来说套用react官方的话就是请确保数组中包含了所有外部作用域//中会随时间变化并且在useMemo中使用的变量都要放到第二个参数中。const Component = useMemo(()=><Index/>, []);return (<div className="App"><button onClick={()=>setState(state+1)}>点我看看子组件刷新了吗</button>{Component}</div>);
}
利用props.children缓存组件
这样在Index组件re-render的时候,由于App(父组件)中的组件没有变化,所以拿到的children依然是上一次的(没有发生变化的)所以children部分不会re-render。
const Index = (props)=> {const [state, setState] = useState(0);return (<div>//当这个按钮点击之后我们发现Children组件并不重新刷新了,其实原理我理解的是react帮我们做了一层//处理当渲染前与渲染后两个组件的引用地址一样他就会放弃render,当然这是我的猜测,这个的话之后//我看到源码的时候会和大家讲一下在补充一下。<button onClick={()=>setState(state+1)}>点我我看看子组件刷新不刷新</button>{props.children}</div>)
};
const Children = ()=> {return (<div>{console.log('子组件刷新了')}这是children组件</div>)
}const App = ()=>{return (<div className="App"><Index><Children/></Index></div>);
}
注意事项
- useCallBack不是每个函数都需要使用!不要滥用useCallback
const Index = (props)=> {console.log('子组件刷新了');return (<div>//点击这个按钮之前先点击App组件下面的按钮,让state变大,然后在点击这个按钮看看state是啥//我们发现state一直是一个0。这是为什么呢,因为很简单我们之前讲了useCallback第二个和//useEffect的第二个参数是一样的,因为我们传递的是空数组说以useCallback一直拿到的是最原始的//值,所以会造成这个问题,我们写代码的时候千万要注意第二个参数,只要useCallback需要什//值我们就在第二个参数传递什么值,这样才可以确保我们拿到的是最新的值。同样的里面如果不需要一些//参数的话我们也不要把这些参数加到第二个参数上面否则会出现func的地址多次改变。<button onClick={props.func}>点我看看state是啥</button>这是子组件</div>)
}
const MemoIndex = React.memo(Index);const App = ()=>{const [state, setState] = useState(0);const func = useCallback(()=> {console.log(state);}, [])return (<div className="App"><button onClick={()=>setState(state+1)}>点我看看子组件刷新了吗</button><MemoIndex func={func}/></div>);
}
- useCallBack是一个缓存工具没错。但实际上他并不能阻止函数都重现构建。
示例:
大家看上方这种结构的组件,Com组件中包含了fun1和fun2两个函数。
是不是认为当Com组件重新渲染的时候,只有fun2(没有使用useCallBack的函数)函数会被重新构建,而fun1(使用了useCallBack的函数)函数不会被重新构建。
实际上,被useCallBack包裹了的函数也会被重新构建并当成useCallBack函数的实参传入。
useCallBack的本质工作不是在依赖不变的情况下阻止函数创建,而是在依赖不变的情况下不返回新的函数地址而返回旧的函数地址。不论是否使用useCallBack都无法阻止组件render时函数的重新创建!!
每一个被useCallBack的函数都将被加入useCallBack内部的管理队列。而当我们大量使用useCallBack的时候,管理队列中的函数会非常之多,任何一个使用了useCallBack的组件重新渲染的时候都需要去遍历useCallBack内部所有被管理的函数找到需要校验依赖是否改变的函数并进行校验。
在以上这个过程中,寻找指定函数需要性能,校验也需要性能。所以,滥用useCallBack不但不能阻止函数重新构建还会增加“寻找指定函数和校验依赖是否改变”这两个功能,为项目增添不必要的负担。
//Com组件
const Com = () => {//示例1包裹了useCallBack的函数const fun1 = useCallBack(() => {console.log('示例一函数');...},[])//示例2没有包裹useCallBack的函数const fun2 = () => {console.log('示例二函数');...}return <div></div>
}
不要过度缓存组件
其实不必过度优化代码 react官方没有帮你做 其实也证明了 如果你的代码没有明显的卡顿 你自己去做优化 可能造成负优化
优化的手段一般都是针对组件本身比较复杂且数据量大每次re-render都会造成卡顿的情况下才去做的,没有太明显的卡顿出现时没必要做这些优化。而且在使用memo前其实也有手段去规避这些无效的re-render,比如将组件粒度划分的更细一些
参考文章
useCallBack你真的知道怎么用吗。
相关文章:
正确使用React组件缓存
简介 正常来讲的话当我们点击组件的时候,该组件以及该组件的子组件都会重新渲染,但是如何避免子组件重新渲染呢,我们经常用memo来解决 React.memo配合useCallback缓存组件 父组件没有传props const Index ()> {console.log(子组件刷新…...
AMEYA360:大唐恩智浦荣获 2023芯向亦庄 “汽车芯片50强”
2023年11月28日,由北京市科学技术委员会和北京市经济和信息化局指导、北京经济技术开发区管理委员会主办、盖世汽车协办的“芯向亦庄”汽车芯片大赛在北京亦庄成功闭幕。 在本次大赛中 大唐恩智浦的 电池管理芯片DNB1168 (应用于新能源汽车BMS系统) 凭卓越的性能及高…...
在Arch Linux上安装yay
有点麻烦。 准备 # pacman -Syu # pacman -S --needed base-devel git 变身为普通用户 不能使用root下载代码。所以要变身为普通用户: # sueradd tsit # su tsit 下载代码 $ git clone https://aur.archlinux.org/yay.git 编译安装 $ cd yay $ makepkg -si…...
PHP案例:探究MySQL应用开发喜好的网络调查
文章目录 一、知识准备(一)数据库与表的创建(二)录入调查选项(三)创建问卷页面(四)处理投票数据(五)显示调查结果二、实现步骤(一)创建数据库与表(二)录入若干调查选项(三)创建问卷页面(四)创建调查结果页面(五)体验运行结果(六)查看最终生成的HTML代码很…...
力扣第374场周赛题解
这一场周赛的题目是比较难的一次,写了1个多小时就写了两个题目。 首先第一题: 纯水题,遍历然后进行一下判断就可以解决了。这边就不放代码了。 第二题: 这个题目,我觉得难度非常大,其实代码量也不大都是很…...
Linux Docker 安装Nginx
1.21、查看可用的Nginx版本 访问Nginx镜像库地址:https://hub.docker.com/_/nginx 2、拉取指定版本的Nginx镜像 docker pull nginx:latest #安装最新版 docker pull nginx:1.25.3 #安装指定版本的Nginx 3、查看本地镜像 docker images 4、根据镜像创建并运行…...
鸿蒙应用开发(二)环境搭建
开发流程 IDE下载 首先下载HUAWEI DevEco Studio,介绍首次启动DevEco Studio的配置向导: 运行已安装的DevEco Studio,首次使用,请选择Do not import settings,单击OK。安装Node.js与ohpm。node.js 是基于 V8 引擎构…...
在 Qt Creator 中编写 Doxygen 风格的注释
2023年12月10日,周日上午 如何生成Doxygen 风格的注释 在需要Doxygen 风格注释的函数上方输入 /**,然后按下 Enter 键。Qt Creator 将自动为你生成一个注释模板。 输入,Qt Creator会自动帮你补全Doxygen标签 不得不说,写了Doxyge…...
NSS [NSSCTF 2022 Spring Recruit]babyphp
NSS [NSSCTF 2022 Spring Recruit]babyphp 考点:PHP特性 开局源码直接裸奔 <?php highlight_file(__FILE__); include_once(flag.php);if(isset($_POST[a])&&!preg_match(/[0-9]/,$_POST[a])&&intval($_POST[a])){if(isset($_POST[b1])&&…...
ToolkenGPT:用大量工具增强LLM
深度学习自然语言处理 原创作者:cola 用外部工具增强大型语言模型(LLM)已经成为解决复杂问题的一种方法。然而,用样例数据对LLM进行微调的传统方法,可能既昂贵又局限于一组预定义的工具。最近的上下文学习范式缓解了这一问题,但有…...
2022蓝桥杯c组求和
题目名字 求和 题目链接 题意 输入的每个数都要两两相乘,然后再加起来,求最后总和; 思路 每个数乘这个数的前缀和即可 算法一:前缀和 实现步骤 先把前缀和写出来再写for循环每个数都乘以自己的前缀和; 实现步骤 直接…...
Altium Designer学习笔记11
画一个LED的封装: 使用这个SMD5050的封装。 我们先看下这个芯片的功能说明: 5050贴片式发光二极管: XL-5050 是单线传输的三通道LED驱动控制芯片,采用的是单极性归零码协议。 数据再生模块的功能,自动将级联输出的数…...
TTS | 2019~2023年最新增强/生成情绪的语音合成调研(20231211更新版)
本博客主要是 增强/生成情绪的语音合成调研,论文按照时间顺序排列,且有些论文为期刊会议论文,有的是arxiv论文,在本文中,标识如下: 【🔊ICML 】【✨Interspeech 】【🫧ICASSP】 20…...
搜狗输入法v模式 | 爱莉希雅皮肤
搜狗输入法v模式 | 爱莉希雅皮肤 前言爱莉希雅皮肤v模式 前言 搜狗输入法有v模式,v模式是一个转换和计算的功能组合。拥有数字转换、日期转换、算式计算、函数计算等功能。本文介绍如何使用v模式,并附赠一个爱莉希雅的皮肤,可通过百度网盘下…...
2023年阿里云云栖大会-核心PPT资料下载
一、峰会简介 历经14届的云栖大会,是云计算产业的建设者、推动者、见证者。2023云栖大会以“科技、国际、年轻”为基调,以“计算,为了无法计算的价值”为主题,发挥科技平台汇聚作用,与云计算全产业链上下游的先锋代表…...
JavaScript实战:制作一个待办事项列表应用
JavaScript实战:制作一个待办事项列表应用 引言 在本教程中,我们将一步步创建一个简单的待办事项列表应用,这不仅会帮助你学习基本的JavaScript编程概念,还会教会你如何处理事件以及操作DOM。这个项目是面向初学者的,…...
4面百度软件测试工程师的面试经验总结
没有绝对的天才,只有持续不断的付出。对于我们每一个平凡人来说,改变命运只能依靠努力幸运,但如果你不够幸运,那就只能拉高努力的占比。 2023年7月,我有幸成为了百度的一名测试工程师,从外包辞职了历经1000…...
textarea文本框回车enter的时候自动提交表单,根据内容自动高度
切图网近期一个bootstrap5仿chatgpt页面的项目遇到的,textarea文本框回车enter的时候自动提交表单,根据内容自动高度,代码如下,亲测可用。 <textarea placeholder"Message ChatGPT…" name"" rows"&q…...
dubbo框架技术文档-《spring-boot整合dubbo框架搭建+配置文件》框架的本地基础搭建
阿丹: 目前流行的微服务更多的就是dubbo和springcould微服务。之前阿丹没有出过dubbo相关的文章,因为之前接触springcould的微服务概念比较多一点,但是相对于springcould来说,springcould服务之间的调用是大多是使用了nacos&#…...
中通快递单号查询入口,将指定某天签收的单号筛选出来
批量查询中通快递单号的物流信息,将指定某天签收的单号筛选出来。 所需工具: 一个【快递批量查询高手】软件 中通快递单号若干 操作步骤: 步骤1:运行【快递批量查询高手】软件,并登录 步骤2:点击主界面左…...
10分钟掌握Deep-Live-Cam:从零搭建实时AI换脸系统的完整指南
10分钟掌握Deep-Live-Cam:从零搭建实时AI换脸系统的完整指南 【免费下载链接】Deep-Live-Cam real time face swap and one-click video deepfake with only a single image 项目地址: https://gitcode.com/GitHub_Trending/de/Deep-Live-Cam Deep-Live-Cam是…...
IntelliJ IDEA中SVN与Git版本管理的高效配置指南
1. 为什么需要版本管理工具? 如果你曾经因为误删代码而熬夜重写,或者因为团队协作时文件覆盖而崩溃,那你一定需要版本管理工具。想象一下,代码就像写作文时的草稿纸——每次修改都保留历史版本,随时可以回退到上周二下…...
sinx/x在0到无穷积分的条件收敛性分析与证明
1. 从物理现象到数学问题:为什么研究sinx/x的积分? 我第一次接触sinx/x的积分是在信号处理课程中,这个看似简单的函数在傅里叶变换和频谱分析中扮演着关键角色。工程师们用它来描述理想低通滤波器的频率响应,物理学家则在衍射现象…...
决策树剪枝实战:用C++和Python分别实现,我踩过的坑你别再踩了
决策树剪枝实战:用C和Python分别实现,我踩过的坑你别再踩了 第一次在C里实现决策树剪枝时,内存泄漏让我调试到凌晨三点;而用Python重写时,又因为没注意NumPy的广播机制导致准确率计算全错。这篇文章记录了我从零实现两…...
从LIF神经元到STDP学习:一个SNN识别MNIST的完整故事线(不只是代码)
从LIF神经元到STDP学习:揭秘脉冲神经网络如何"看见"数字 想象一下,当你看到数字"7"时,大脑中的神经元是如何协同工作,让你瞬间识别出这个符号的?这正是脉冲神经网络(SNN)试图模拟的生物智能过程。…...
危废尾气治理厂家怎么选?CO超低排放技术与全场景危废焚烧烟气治理解决方案
随着我国危废处置行业监管体系持续完善,《危险废物焚烧污染控制标准》(GB 18484-2020)对危废焚烧烟气中一氧化碳(CO)等污染物设置了明确排放限值,北京、海南等多地更是出台严于国标的地方标准,其…...
intv_ai_mk11效果展示:中文古诗英译+文化注释+押韵风格选择(Shakespearean/Modern)
intv_ai_mk11效果展示:中文古诗英译文化注释押韵风格选择(Shakespearean/Modern) 1. 惊艳的中英古诗翻译能力 intv_ai_mk11在中文古诗翻译领域展现出令人惊叹的能力,不仅能准确传达原诗的意境,还能根据需求选择不同的…...
智能化时代的数据集成技术革新
在技术领域,我们常常被那些闪耀的、可见的成果所吸引。今天,这个焦点无疑是大语言模型技术。它们的流畅对话、惊人的创造力,让我们得以一窥未来的轮廓。然而,作为在企业一线构建、部署和维护复杂系统的实践者,我们深知…...
终极指南:一键解决iPhone USB网络共享驱动问题
终极指南:一键解决iPhone USB网络共享驱动问题 【免费下载链接】Apple-Mobile-Drivers-Installer Powershell script to easily install Apple USB and Mobile Device Ethernet (USB Tethering) drivers on Windows! 项目地址: https://gitcode.com/gh_mirrors/ap…...
Python 如何反向 `enumerate` 遍历枚举
在 Python 中,enumerate() 是一个常用的内置函数,用于在遍历可迭代对象(如列表、元组、字符串等)时同时获取索引和值。但默认情况下,enumerate() 是从前往后遍历的。那么,**如何反向 enumerate 遍历&#x…...
