当前位置: 首页 > article >正文

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

在这里插入图片描述

文章概叙

本文主要讲的是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.kler.cn/a/229468.html

相关文章:

  • RNN之:LSTM 长短期记忆模型-结构-理论详解-及实战(Matlab向)
  • Kafka——两种集群搭建详解 k8s
  • JAVA:利用 RabbitMQ 死信队列实现支付超时场景的技术指南
  • 使用 configparser 读取 INI 配置文件
  • 后端技术选型 sa-token校验学习 下 结合项目学习 后端鉴权
  • C++内存泄露排查
  • 【ArcGIS微课1000例】0101:删除冗余节点或折点
  • 计算机网络——03网络核心
  • 详解Python3的垃圾回收机制
  • 国内领先的酒店用品采购平台「尚和酒店」×企企通B2B2B商城上线,引领酒店用品行业数智升级
  • 在 CentOS 7上使用 Apache 和 mod_wsgi 部署 Django 应用的方法
  • Nginx使用详解
  • 6、基于机器学习的预测
  • 4. 树(二叉树、二叉查找树/二叉排序树/二叉搜索树、平衡二叉树、平衡二叉B树/红黑树)
  • 【JavaScript】Js中一些数组常用API总结
  • 面试数据结构与算法总结分类+leetcode目录【基础版】
  • 流量控制原理
  • SSRF漏洞给云服务元数据带来的安全威胁
  • k8s学习(RKE+k8s+rancher2.x)成长系列之简配版环境搭建(二)
  • 基于最新koa的Node.js后端API架构与MVC模式
  • (附源码)基于springboot 毕业生去向统计设计系统-计算机毕设 25559
  • Web 站点的欢迎页面
  • MYSQL performance schema详解
  • zk集群--集群同步
  • 麒麟V10系统下离线安装docker-compose
  • 书客/霍尼韦尔/柏曼大路灯哪款好?多维度真实测评!买对不买贵!