react性能优化之memo的作用和memo的坑

news2024/11/18 13:30:45

前言

在react中,组件渲染的是最常有的事情。但是,有部分的渲染是不必要的,是可以避免的。

在react的一般规则中,只有父组件的某一个状态改变,父组件下面所有的子组件不论是否使用了该状态,都会进行重新渲染。

显然,对于没有用到被改变的那个状态的组件来说,重新渲染是完全没有必要的。所以,React.memo就诞生了。

父组件中状态的改变会让所有的子组件重新渲染

举个例子 ↓
在这里插入图片描述
在这里插入图片描述

上面的例子中,我们有两个state,一个buibuibui,一个tututu。被传入children组件的是tututu,在父组件中改变的是buibuibui。

问:当父组件的buibuibui这个state被改变的时候,只接收了tututu这个变量的children(子组件)会被重新渲染吗。

答:会的,只要父组件的状态改变,所有的子组件不论是否使用到了被改变的那个state都会被重新渲染。

如图↓
在这里插入图片描述

显然这种渲染是完全没必要的。我又没有使用被改变的那个state,我本身本身也没有什么视图需要更新,根本没必要重新渲染。

在阻止重新渲染这个需求的基础上,诞生了memo(),memo是react的一种缓存技术,这个函数可以检测从父组件接收的props,并且在父组件改变state的时候比对这个state是否是本组件在使用,如果不是,则拒绝重新渲染。

memo 和它的使用方式

并且它的使用方法也非常的简单。只需要在把子组件当成这个函数的入参包起来就好了。

例如↓
在这里插入图片描述

像这样,这Children就是被缓存成功了。下次当父组件中无关它的state(状态)被更新时候,Children组件就不会重新渲染。

在这里插入图片描述

参考上面的例子去介绍memo()就是

子组件被memo函数保护了。当父组件中一切无关子组件的state被改变时,子组件拒绝重新渲染,这样节省了性能。

而上面的例子中,传入Children组件的是tututu这个状态。而父组件中被改变的是buibuibui这个state。buibuibui被改变与Children无关,因为children被memo保护,所以chidren不重新渲染

反之,如果children组件没有被memo保护,那么即使被改变的buibuibui这个state与children组件无关。children组件也会被重新渲染。

总而言之就是,如果当前组件被memo保护,那么当前组件的props不变,则组件不进行重新渲染。这样,我们合理的使用memo就可以为我们的项目带来很大的性能优化。

以上,就是关于react的组价缓存。

memo的坑

上面说了memo的用处和好处。
下面我们来说memo坑的地方

第一个坑

有那么一种情况,被memo的保护的组件即使props变了,它也不会重新渲染。
当被改变的那个props是一个数组(对象)的时候
例如↓
在这里插入图片描述
在这里插入图片描述

上图中,传入了一个list数组进去子组件,子组件内部是被memo缓存了的。这个时候,如果我们往list这个数组中push()一个6,那么子组件中的props改变了,理论上来说,子组件应该重新渲染了。但实际上并不会。

这是为什么呢?因为memo的保护是对props做一个浅比较(不了解什么是浅比较的同学点这里)

而数组的使用push()方法看似是变了。但变的只是堆中的数据,存在与栈中的地址依然不会改变。memo是检测不到的。所以,使用push等不能返回一个新数组的方法,均无法触发memo的更新机制。

如图↓
在这里插入图片描述

想要改变数组也能让子组件更新,有方法。
就像刚刚说的,需要让memo检测到数组栈地址的变化。要栈地址变化的话,只要返回一个全新的数组就好了。

所以,我们不妨将代码做出以下修改。

	const [list,setList] = useState([1,2,3,4,5]);
	
	setList(list.push(1)); //这样是不会被memo检测到的,是无法触发memo更新的
	
	setList([...list,1]); //这样才可以,创建一个新数组,再在里面解构旧数组,往后面追加 1
	//这样,就等于返回了一个新的数组,栈中的地址就会改变,memo就可以检测到并触发更新

这样,就可以既修改数组,又触发组件更新了

第二个坑

对!还有第二个坑!!

memo是不是很好用?是不是有那么好的东西恨不得每个组件都包一下?

这就是它坑的地方了,它不能每个组件都包一下。

倒不是说全包就报错,只是如果全包的话,还不如不包。

话说回来,如果真的每个组件都有被缓存的必要而且不会给项目带来破坏性问题,为什么react不直接把memo设为默认的呢。当然是因为每个都缓存的话,会给项目带来毁灭性的问题咯。

我们需要知道的是,缓存也需要成本。如果每个组件都进行缓存,会给浏览器带来非常非常大的负担。

所以在平常项目中,我们需要挑选一些经常被使用,经常会被重新渲染的组件去有目标的缓存他。而不是每一个组件都缓存一下。切记切记。

总结

  • 父组件中state(状态)改变,不受memo保护的子组件也会重新渲染
  • memo会检测props到改变来决定组件是否需要进行重新渲染,换言之就是,被memo函数包起来的组件只有本身的props被改变之后才会重新渲染
  • memo只能进行浅拷贝来校验决定是否触发重新渲染。所以改变数组(对象)的props时候记得返回一个全新的数组(对象)
  • memo不是项目中所有的组件都需要包一下。包的太多反而会起反效果,我们需要选择那些经常被重新渲染的组件有选择性的去缓存。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[vue+element-ui] form中输入框无法输入问题的解决方法

目录 一.问题发现: 二.正确案例与错误原理: 三.问题解决 一.问题发现: 笔者在制作登录页面前端时使用elementuivue技术,发现输入框无法输入任何内容。 在csdn上查阅很多文章后发现都无法解决,于是去elementui官网进…

谷歌浏览器插件HackBar安装方法(详细教程)

文章目录1.下载压缩包2.将压缩包添加至扩展程序3.修改配置文件4.功能说明1.下载压缩包 链接:https://pan.baidu.com/s/1XOKo_ILZv8PcJihoc8981A?pwd3ha8 提取码:3ha8 注意:下载即可,不用解压。 2.将压缩包添加至扩展程序 打开…

【小程序项目开发-- 京东商城】uni-app之自定义搜索组件(中)-- 搜索建议

🤵‍♂️ 个人主页: 计算机魔术师 👨‍💻 作者简介:CSDN内容合伙人,全栈领域优质创作者。 🌐 推荐一款找工作神器网站: 点击跳转牛客网 |笔试题库|面试经验|实习招聘内推| 还没有账户的小伙伴 速速点击链接…

文本超出部分显示省略号

我们经常在网站上可以看到以下样式,标题太长,一行显示不下,则会使用省略号来代替。但是事实上,这个省略号并不是打字打上去的,而是使用代码表示出来的。 今天则主要介绍如何让文本超出部分显示省略号。 1.单行文本超出…

关于HTML中常用选择器

一.五种基本选择器: 1)*:匹配HTML中所有元素,一般用于除去内边距和外边距,其性能较差,不推荐使用; 2)标签名(在JavaScript中也称节点):标签选择器。注意在用标签修改样式…

如何创建一个Servlet项目(Maven)?

系列文章目录 Tomcat下载、安装及使用介绍_crazy_xieyi的博客-CSDN博客 文章目录 前言一、创建Servlet项目(Maven)的步骤 1.创建Maven项目2.引入依赖3.创建目录4.编写代码5.打包程序6.部署程序7.验证程序二、总结(使用smart tomcat插件来打包…

微信小程序开发前端基础知识

文章目录一、简介1、是什么2、为什么二、准备工作1、环境准备1.1、注册账号1.2、获取APPID1.3、开发工具2、创建微信小程序三、组件1、目录及其作用介绍2、页面操作3、view 块级元素4、<navigator>导航跳转5、scroll-view滚动6、text 行标签7、swiper 轮播8、常用表单组件…

Vue语法与标签的使用

前言&#xff1a;最近两周一直在忙于公司业务的学习&#xff0c;一直没有时间进行总结&#xff0c;作为后端开发人员来说&#xff0c;需要了解一些前端的知识&#xff0c;因此今天把最近复习的Vue的知识总结了一下&#xff0c;希望能加深总结的印象以及帮助到各位大佬。 如果有…

React 入门(超详细)

目录前言&#xff1a;一、React 简介1. 什么是 React2. React 的特点3. React 高效的原因4. React 官网5. React的主要原理6. Facebook为什么要建造React?二、React 的基本使用1. 基础代码2. 效果3. 相关 js 库4. 创建虚拟DOM的两种方式5. 虚拟DOM与真实DOM6. 虚拟DOM与真实DO…

Chrome谷歌浏览器安装与配置教程

谷歌浏览器&#xff0c;界面简洁明了、浏览速度相当快&#xff0c;浏览器中的霸主地位 1、在电脑浏览器中打开下载地址https://www.google.cn/chrome/或百度www.baidu.com搜索“chrome”&#xff0c;打开谷歌官方网站 2、进入官网后单击“下载Chrome” 如果下载之后找不到&a…

vue基于element实现动态表格

前言 大家都知道 element 表格组件的表头是静态写死的&#xff0c;我们在渲染数据时只需要将接口返回的数组动态绑定给 data 属性&#xff0c;然后再通过 prop 去对应字段项即可&#xff1b;但是静态的表头并不能满足一些特殊的使用场景&#xff0c;所以我们需要将它变成活的&a…

从0到1构建springboot web应用镜像并使用容器部署

文章目录一、生成镜像的两种方法1.1、使用commit生成镜像1.1.1、拉取Centos基础镜像1.1.2、启动Centos容器并安装Go1.1.3、commit生成新镜像1.1.4、使用新镜像验证Golang环境1.2、使用Dockerfile生成镜像二、基于Dockerfile生成一个springboot镜像2.1、准备springboot应用jar包…

Vue父子组件传值

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、Vue父子传值的方法二、方法详解1.props / $emit2.$parent / children3.$ref总结前言 例如&#xff1a;Vue的学习是路阻且艰的&#xff0c;这是一个系列文章…

微信小程序 | 人脸识别的最终解决方案

&#x1f4cc;个人主页&#xff1a;个人主页 ​&#x1f9c0; 推荐专栏&#xff1a;小程序开发成神之路 --(这是一个为想要入门和进阶小程序开发专门开启的精品专栏&#xff01;从个人到商业的全套开发教程&#xff0c;实打实的干货分享&#xff0c;确定不来看看&#xff1f; &…

Cookie 和 Session的区别

文章目录时间&#xff1a;2023年3月23日第一&#xff1a;什么是 Cookie 和 Session ?什么是 Cookie什么是 Session第二&#xff1a;Cookie 和 Session 有什么不同&#xff1f;第三&#xff1a;为什么需要 Cookie 和 Session&#xff0c;他们有什么关联&#xff1f;第四&#x…

【Java基础】一个Java文件可以有多个类(外部类、内部类)

目录一、在一个Java文件中定义多个类&#xff08;外部类&#xff09;1.问题描述及解答2.总结二、在一个Java文件定义多个类&#xff08;内部类&#xff09;1.成员内部类和匿名内部类1.1 成员内部类1.2 匿名内部类2.深入理解内部类3.内部类的使用场景和好处一、在一个Java文件中…

小米商城官网(登录页,首页,详情页,我的购物车页,我的订单页,确认订单页)HTML+CSS+JS

文章目录前言一、登录页二、首页三、我的购物车页四、我的订单页五、确认订单页六、详情页七、整体结构和效果图总结前言 仿小米商城官网项目是本人实训内容&#xff0c;实训老师带着做的首页和登录页&#xff0c;本人在此基础上加入了我的购物车页&#xff0c;我的订单页&…

vue兼容ie11(@babel/polyfill、core-js@3两种方式)

Babel介绍&#xff1a; Babel是一个JavaScript编译器&#xff0c;主要用于将ECMAScript 2015代码转换为当前和旧浏览器或环境中向后兼容的JavaScript版本。要是通过核心依赖core-js2&#xff0c;主要是通过核心依赖core-js2来完成对应浏览器不支持的新的全局和实例api的添加 …

Vue2 实现图片的拖拽、缩放、旋转

本文是基于vue2 实现图片的拖拽、旋转、鼠标滚动放大缩小等功能。 效果图 分步骤实现 在这里看下 拖拽、旋转、缩放的几个方法 1.获取图片的实际宽高 getImgSize(url) {return new Promise((resolve, reject) > {let imgObj new Image();imgObj.src url;imgObj.onload…

插槽(slot)的基本使用

插槽&#xff08;slot&#xff09;的基本使用 一、插槽的作用 在开发中&#xff0c;我们会经常封装一个个可复用的组件&#xff1a; 前面我们会通过props传递给组件一些数据&#xff0c;让组件来进行展示&#xff1b; 但是为了让这个组件具备更强的通用性&#xff0c;我们不能…