在每个地方都应该添加 memo 吗?

news2024/11/17 6:52:13

在这里插入图片描述

文章概叙

本文主要讲的是React中memo的使用,以及考虑是否使用memo的判断依据

memo介绍

memo 允许你的组件在 props 没有改变的情况下跳过重新渲染。

在使用memo将组件包装起来之后,我们可以‍获得该组件的一个 记忆化 版本。通常情况下,只要该组件的 props 没有改变,这个记忆化版本就不会在其父组件重新渲染时重新渲染。

也正是因为如此,在开发过程中,我们都会说“用memo来缓存组件,跳过组件的重复渲染”等说法,此时所说的memo就是该API,当我们传入的props没有变化(需要注意的是,数组等对象,引用地址不能变化),组件就不会被重新渲染了,就能适当的减少我们的开支~

简单示例

下面的例子中,父组件包括了一个循环的定时器,以及一个子组件,不过对子组件传入的是一个固定的值,代码如下

//父组件的代码
import React, { useEffect, useState } from "react";
import "./App.css";
import MemoComponent from "./components/MemoComponent";function App() {
  const [date, setDate] = useState(0);
  useEffect(() => {
    setInterval(() => {
      setDate(+new Date());
    }, 1000);
  }, []);
  return (
    <div className="App">
      <p>{date}</p>
      <MemoComponent num_array={1} />
    </div>
  );
}export default App;
//子组件的代码
export default (props: any) => {
  console.log("子组件是否刷新");
  return (
    <>
      <div>这个是其中一个子组件</div>
    </>
  );
};

而由于父组件的一直刷新,所以我们的子组件也会跟着被重新渲染。

此时,我们在考虑如何优化我们的组件时,方向就很明显了,就是当计时器一直刷新的时候,我们的子组件并不需要一直刷新。

那么这时候我们就可以使用memo来跳过子组件的重新渲染。
在这里插入图片描述

memo语法

memo(Component, arePropsEqual)

  • Component
    我们需要进行记忆化的组件,react并不会对其做任何的修改,只是做一个高阶组件的处理,添加完自己的操作后返回给你。

  • arePropsEqual
    可选参数,接受两个参数:组件的前一个 props 和新的 props。一般情况我们不需要去管他,直接忽略他,因为React会使用Object.js去判断前后props是否相同,如果我们手动设置了,会很容易出啥错。

使用memo

理解了memo的语法之后,我们可以在我们的子组件中,使用memo将组件包含起来,使其跳过重复渲染,代码如下

//子组件的代码
import { memo } from "react";export default memo((props: any) => {
  console.log("子组件是否刷新");
  return (
    <>
      <div>这个是其中一个子组件</div>
    </>
  );
});


此时,由于我们使用memo,子组件避免了无用的重复渲染,所以控制台就不会一直显示子组件被渲染的情况了。
在这里插入图片描述

memo的地址判断

上章提及到,memo会判断我们传入的props是否一样,但当我们传入一个数组(或者对象)的时候,我们会发现我们的页面中,子组件又被重新渲染了。

 //父组件代码
  <MemoComponent num_array={[1,2,3,4]} />

这是因为,当我们使用数组或者是对象的时候,由于使用的Object.js在判断对象是否一致的时候,会判断引用地址,所以我们看起来值一样,但是实际上不是同一个(参考js数据类型)。

此时我们可以使用useState来保证数组不被重新赋值。

//父组件的代码
import React, { useEffect, useState } from "react";
import "./App.css";
import MemoComponent from "./components/MemoComponent";function App() {
  const [date, setDate] = useState(0);
  const [numArray,setNumArray]=useState([1,2,3,4,5])
  useEffect(() => {
    setInterval(() => {
      setDate(+new Date());
    }, 1000);
  }, []);
  return (
    <div className="App">
      <p>{date}</p>
      <MemoComponent numArray />
    </div>
  );
}export default App;

使用了useState之后,由于我们的numArray的每次都是一样的值,一样的地址,子组件就不会被重新刷新了。

所以当你使用memo之后,发现你的项目并没有按照你的预想走的时候,可以检查下你的组件的props。

滥用memo

既然memo有那么多的好处,那为什么我们的项目中没有出现所有的组件都用memo包起来呢?

下面的例子中,我们使用了memo包括了10个组件,且在5s后,我们的父组件会刷新一次页面,而子组件的代码不变。

//父组件代码
import React, { useEffect, useState } from "react";
import "./App.css";
import MemoComponent from "./components/MemoComponent";function App() {
  const [date, setDate] = useState(0);
  useEffect(() => {
    setTimeout(() => {
      setDate(+new Date());
    }, 5000);
  }, []);
  return (
    <div className="App">
      <p>{date}</p>
      {new Array(10).fill(1).map((v) => (
        <MemoComponent />
      ))}
    </div>
  );
}export default App;


下面是使用了memo处理组件的情况下,大概理解为当计时器触发之后,我们的页面花了14ms来重新渲染我们的页面(3915-3901)

在这里插入图片描述

但是当我们去掉了代码中的memo之后,我们发现,计时器触发之后,我们的页面只需要花费11ms(3388-3377)的时间来渲染。
在这里插入图片描述

你以为我会跟借此跟你说,当给每一个组件都添加了memo之后,由于props的判断会导致页面渲染更多时间吗?​

官网上提及到下面这段话

只有当你的组件经常使用完全相同的 props 重新渲染时,并且其重新渲染逻辑是非常昂贵的,使用 memo
优化才有价值。如果你的组件重新渲染时没有明显的延迟,那么 memo 就不必要了。请记住,如果传递给组件的 props
始终不同,例如在渲染期间传递对象或普通函数,则 memo 是完全无用的。这就是为什么你通常需要在 memo 中同时使用 useMemo 和
useCallback

众所周知,我们的react是通过判断props是否发生变化的来判定是否重新渲染组件的,那么我们可以理解,当我们用一个很复杂的props来节省一个很简单的子组件的时候,我们是否就已经失败了呢?

因为我们的react需要先去判断props是否相同,而当花费了30ms的时间在判断props后,结果只是缓存了一行文字…你猜react会不会气抖冷?

毕竟你去吃饭,老板弄了一道高数题,说解出来了,答案就是wifi密码,你千辛万苦解出来,发现老板家的wifi只有1k/s,不单单打扰你跟小姐姐聊天,还用你手机挖矿,你就知道什么感觉了。

至于React的memo是否会占用多一些空间缓存的,由于本人没有具体的demo,所以推荐大家看下github上的答复,就不验证了​​

在这里插入图片描述

一个前端博客,希望能帮到小白们

公众号求关注~

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

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

相关文章

14.0 Zookeeper环球锁实现原理

全局锁是控制全局系统之间同步访问共享资源的一种方式。 下面介绍zookeeper如何实现全民锁&#xff0c;讲解他锁和共享锁两类全民锁。 排他锁 排他锁&#xff08;Exclusive Locks&#xff09;&#xff0c;又被称为写锁或独占锁&#xff0c;如果事务T1对数据对象O1加上排他锁…

可解释性AI(XAI)的主要实现方法和研究方向

文章目录 每日一句正能量前言主要实现方法可解释模型模型可解释技术 未来研究方向后记 每日一句正能量 当你还不能对自己说今天学到了什么东西时&#xff0c;你就不要去睡觉。 前言 随着人工智能的迅速发展&#xff0c;越来越多的决策和任务交给了AI系统来完成。然而&#xff…

问题:下列关于海关统计项目的表述,正确的有:A.进出境货物的统计重量和数量应以报关单位申报的重量和数 #笔记#职场发展#媒体

问题&#xff1a;下列关于海关统计项目的表述&#xff0c;正确的有&#xff1a;A&#xff0e;进出境货物的统计重量和数量应以报关单位申报的重量和数 下列关于海关统计项目的表述&#xff0c;正确的有&#xff1a; A&#xff0e;进出境货物的统计重量和数量应以报关单位申报的…

【初识爬虫+requests模块】

爬虫又称网络蜘蛛、网络机器人。本质就是程序模拟人使用浏览器访问网站&#xff0c;并将需要的数据抓取下来。爬虫不仅能够使用在搜索引擎领域&#xff0c;在数据分析、商业领域都得到了大规模的应用。 URL 每一个URL指向一个资源&#xff0c;可以是一个html页面&#xff0c;一…

Pandas教程11:关于pd.DataFrame.shift(1)数据下移的示例用法

---------------pandas数据分析集合--------------- Python教程71&#xff1a;学习Pandas中一维数组Series Python教程74&#xff1a;Pandas中DataFrame数据创建方法及缺失值与重复值处理 Pandas数据化分析&#xff0c;DataFrame行列索引数据的选取&#xff0c;增加&#xff0c…

Oracle Vagrant Box 扩展根文件系统

需求 默认的Oracle Database 19c Vagrant Box的磁盘为34GB。 最近在做数据库升级实验&#xff0c;加之导入AWR dump数据&#xff0c;导致空间不够。 因此需要对磁盘进行扩容。 扩容方法1&#xff1a;预先扩容 此方法参考文档Vagrant, how to specify the disk size?。 指…

Postman发送带登录信息的请求

环境&#xff1a;win10Postman10.17.7 假设有个请求是这样的&#xff1a; RequiresPermissions("tool:add") PostMapping(value"/predict") ResponseBody /** * xxx * param seqOrderJson json格式的参数 * return */ public String predictSampleIds(Req…

蓝桥杯省赛无忧 课件125 线段树-标记永久化

前置知识 线段树 01 什么是标记永久化 02 如何标记永久化 03 标记永久化的优势

RabbitMQ-2.SpringAMQP

SpringAMQP 2.SpringAMQP2.1.创建Demo工程2.2.快速入门2.1.1.消息发送2.1.2.消息接收2.1.3.测试 2.3.WorkQueues模型2.2.1.消息发送2.2.2.消息接收2.2.3.测试2.2.4.能者多劳2.2.5.总结 2.4.交换机类型2.5.Fanout交换机2.5.1.声明队列和交换机2.5.2.消息发送2.5.3.消息接收2.5.4…

OpenCV/C++:点线面相关计算(二)

接续&#xff0c;继续更新 OpenCV/C:点线面相关计算_线面相交的点 代码计算-CSDN博客文章浏览阅读1.6k次&#xff0c;点赞2次&#xff0c;收藏12次。OpenCV处理点线面的常用操作_线面相交的点 代码计算https://blog.csdn.net/cd_yourheart/article/details/125626239 目录 1、…

前端工程化之:webpack3-5(css module)

目录 一、css module 1.思路 2.实现原理 3.如何应用样式 4.其他操作 &#xff08;1&#xff09;全局类名 &#xff08;2&#xff09;如何控制最终的类名 5.其他注意事项 一、css module 通过命名规范来限制类名太过死板&#xff0c;而 css in js 虽然足够灵活&…

CleanMyMac X 4.14.7帮您安全清理Mac系统垃圾

CleanMyMac X 4.14.7是一款强大的 Mac 清理、加速工具和健康卫士,可以让您的 Mac 再次恢复巅峰性能。 移除大型和旧文件、卸载应用,并删除浪费磁盘空间的无用数据。 5倍 更多可用磁盘空间 CleanMyMac X 4.14.7帮您安全清理Mac系统垃圾 CleanMyMac X 4.14.7一键深度扫描mac系统…

正点原子-STM32通用定时器学习笔记(1)

1. 通用定时器简介&#xff08;F1为例&#xff09; F1系列通用定时器有4个&#xff0c;TIM2/TIM3/TIM4/TIM5 主要特性&#xff1a; 16位递增、递减、中心对齐计数器&#xff08;计数值&#xff1a;0~65535&#xff09;&#xff1b; 16位预分频器&#xff08;分频系数&#xff…

安装python详细步骤(超详细,保姆级,一步一图)_python 安装

前言 作为一个实用学习的主义的学习者&#xff0c;最关心的问题一定是“我为什么要学习 Python&#xff0c;学会之后我可以用来做什么&#xff1f;” 首先&#xff0c;对于初学者来说&#xff0c;比起其他编程语言&#xff0c;Python更容易上手。 Python 的设计哲学是优雅、明…

C语言:内存函数

创作不易&#xff0c;友友们给个三连吧&#xff01;&#xff01; C语言标准库中有这样一些内存函数&#xff0c;让我们一起学习吧&#xff01;&#xff01; 一、memcpy函数的使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); 1.1 使…

高速接口PCB布局指南(二)通用高速信号布线

高速接口PCB布局指南&#xff08;二&#xff09;通用高速信号布线 1.PCB材料编织2.高速信号布线长度3.高速信号布线长度匹配4.高速信号参考平面 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 1.PCB材料编织 在常见的 PCB 材料上为差分信号布线时&#xff0c;…

基于SSM的协同过滤技术的网上书城(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的协同过滤技术的网上书城&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Sp…

深入理解vqvae

深入理解vqvae TL; DR&#xff1a;通过 vector quantize 技术&#xff0c;训练一个离散的 codebook&#xff0c;实现了图片的离散表征。vqvae 可以实现图片的离散压缩和还原&#xff0c;在图片自回归生成、Stable Diffusion 中&#xff0c;有重要的应用。 从 AE 和 VAE 说起 …

【Nicn的刷题日常】之打印整数二进制的奇数位和偶数位

目录 1.题目描述 2.解题思路 3.解题 1.题目描述 获取一个整数二进制序列中所有的偶数位和奇数位&#xff0c;分别打印出二进制序列 2.解题思路 1. 提取所有的奇数位&#xff0c;如果该位是1&#xff0c;输出1&#xff0c;是0则输出0 2. 以同样的方式提取偶数位置检测n…

k8s学习(RKE+k8s+rancher2.x)成长系列之简配版环境搭建(二)

三、简配版集群&#xff0c;适用于demo环境 1.集群架构设计 主机名角色配置(核数&#xff0c;内存&#xff0c;磁盘)MasterRKE,controlplane,etcd,worker,rancher-master2C 8G 40GSlaver1controlplane,worker,rancher-master2C 8G 40GSlaver2controlplane,worker,rancher-mas…