React Hook 之 useMemo及 React.memo

2023-10-27

一、useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

返回一个 memoized 值。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

记住,传入useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect的适用范畴,而不是 useMemo

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

以下举例说明:

  1. 父组件
function App() {
  const [name, setName] = useState('名称')
  const [content,setContent] = useState('内容')
  return (
      <>
        <button onClick={() => setName(new Date().getTime())}>name</button>
        <button onClick={() => setContent(new Date().getTime())}>content</button>
        <Button name={name}>{content}</Button>
      </>
  )
}
  1. 子组件
function Button({ name, children }) {
  function changeName(name) {
    console.log('11')
    return name + '改变name的方法'
  }

  const otherName =  changeName(name)
  return (
      <>
        <div>{otherName}</div>
        <div>{children}</div>
      </>

  )
}

熟悉react的同学可以很显然的看出,当我们点击父组件的按钮的时候,子组件的namechildren都会发生变化。
不管我们是改变name或者content的值,我们发现 changeName的方法都会被调用。
是不是意味着 我们本来只想修改content的值,但是由于name并没有发生变化,所以无需执行对应的changeName方法。但是发现他却执行了。 这是不是就意味着性能的损耗,做了无用功。

  1. 优化之后的子组件
function Button({ name, children }) {
  function changeName(name) {
    console.log('11')
    return name + '改变name的方法'
  }

const otherName =  useMemo(()=>changeName(name),[name])
  return (
      <>
        <div>{otherName}</div>
        <div>{children}</div>
      </>

  )
}

export default Button

这个时候我们点击 改变content值的按钮,发现changeName并没有被调用。
但是点击改变name值按钮的时候,changeName被调用了。
所以我们可以使用useMemo方法 避免无用方法的调用,当然一般我们changName里面可能会使用useState来改变state的值,那是不是就避免了组件的二次渲染。达到了优化性能的目的。

二、React.memo
import React, { useState } from 'react'
const Child = props => {
    console.log("render child")
    return (
        <div>
            props count: { props.count }
        </div>
    )
}
const Wrapper = () => {
    const [count, setCount] = useState(0)
    const [id, setId] = useState(0)

    return (
        <div>
            <h2>React Memo</h2>
            <button onClick={() => setId(id + 1)}>render parent</button>
            <button onClick={() => setCount(count + 1)}>change count</button>
            <Child count={count}></Child>
        </div>
    )
}

export default Wrapper

上述例子中,我们每次点击 render parent 按钮,Wrapper组件就会重新渲染,导致Child组件也会重新渲染打印"render child",但实际上,Childprops并未改变,所以不需要render

class component中,我们可以使用 PureComponentshouldComponentUpdate 来控制子组件是否需要渲染.

但在FC中没这些玩意儿该怎么办?

解决方式是用React.memo将子组件 child 包裹起来:

import React, { useState } from 'react'
const Child = props => {
    console.log("render child")
    return (
        <div>
            props count: { props.count }
        </div>
    )
}

const Memo = React.memo(Child)

const Wrapper = () => {
    const [count, setCount] = useState(0)
    const [id, setId] = useState(0)

    return (
        <div>
            <h2>React Memo</h2>
            <button onClick={() => setId(id + 1)}>render parent</button>
            <button onClick={() => setCount(count + 1)}>change count</button>
            <Memo count={count}></Memo>
        </div>
    )
}

这样,只要在我们修改了count的情况下,子组件才会渲染

不仅如此,React.memo还提供了第二参数,一个函数,用来自定义判断前后是否相等,类似

shouldComponentUpdate,只不过返回值相反。

我们把上面的例子改为如果新的count值比老的count的差值值大于等于2Child`才能渲染:

import React, { useState } from 'react'
const Child = props => {
    console.log("render child")
    return (
        <div>
            props count: { props.count }
        </div>
    )
}

const Memo = React.memo(Child, (prev, next) => {
    return (next.count - prev.count) < 2
})
const Wrapper = () => {
    const [count, setCount] = useState(0)
    const [id, setId] = useState(0)

    return (
        <div>
            <h2>React Memo</h2>
            <button onClick={() => setId(id + 1)}>render parent</button>
            <button onClick={() => setCount(count + 1)}>change count</button>
            <Memo count={count}></Memo>
        </div>
    )
}

现在就是点两次change count按钮,才会触发render child

参考:
  1. https://zh-hans.reactjs.org/docs/hooks-reference.html#usememo
  2. https://segmentfault.com/a/1190000018697490
  3. https://zhuanlan.zhihu.com/p/339438975
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React Hook 之 useMemo及 React.memo 的相关文章

随机推荐

  • 服务器可以向客户端传文件,服务器可以向客户端传文件

    服务器可以向客户端传文件 内容精选 换一换 Web服务端证书用于客户端浏览器和web服务器之间的通讯 实现数据信息在客户端和web服务器之间的加密传输 可以防止数据信息的泄露 为提高安全性 建议替换成自己的证书 并及时更新证书 保证证书的有
  • 企业级 CICD 工具部署 Serverless 应用的落地实践

    作者 李鑫 缤智 阿里云高级技术专家 背景知识 通过以往几节课程的学习 相信大家对于 SAE 平台已经有了一定的了解 SAE 为客户免除了很多复杂的运维工作 开箱即用 按用量付费 与此同时 SAE 提供了丰富的 Open API 可以很容易
  • Linux系统安装gcc/g++详细过程

    个站持续更新 码到城攻码到城攻专注于IT技术 资源分享https www codecomeon com 下载 http ftp gnu org gnu gcc gcc 4 5 1 gcc 4 5 1 tar bz2 浏览 Index of
  • 手撕《数字信号处理》——通俗易懂的数字信号处理章节详解集合

    第一章 基本信号的认识 第一节 基本的信号 正弦信号与正弦序列 matlab正弦信号代码 清泉 流响的博客 CSDN博客 第二节 基本的信号 指数信号与指数序列 清泉 流响的博客 CSDN博客 第三节 基本的信号 Sa函数 抽样信号 清泉
  • 一篇文章带你了解区块链的工作原理与流程

    大家好 我是晴天defi 区块链这段时间相当热门 新闻媒体大量的报道 宣称它将创造未来 但啥是区块链 它是如何工作 有何特别之处 能解决什么问题 又如何使用呢 今天我们就来尝试 做一个最好懂的区块链教程 希望你看完这篇文章 不仅可以理解区块
  • ACS712 电流传感器

    ACS712 电流传感器 ACS712 是基于霍尔效应的电流传感器 简介 ACS712 框图 ACS712 引脚如下表 其中 I P IP IP 和 I P
  • [深入研究4G/5G/6G专题-53]: L3信令控制-2-软件功能与流程的切分-DU网元的信令

    目录 第1章 软件架构 第2章 5G CP RT 实时 2 1 功能概述 2 2 功能细化 2 3 线程管理 第1章 软件架构
  • UE4_C++调用蓝图里的事件

    目前网上的大多数方法都是 在c 中定义一个基类 然后让蓝图去实现或者 在此提供 另外两种方法 CallFunctionByNameWithArguments 函数名称Foo 参数xxx FOutputDeviceNull OutputDev
  • SpringBoot面试题(持续整理中……)

    Spring Boot 是微服务中最好的 Java 框架 为了更好的理解与使用SpringBoot 同时 为了记录平时的点点滴滴 便于日后的面试 1 什么是SpringBoot 用来简化Spring应用的初始搭建以及开发过程 使用特定的方式
  • 位运算的使用

    1 如何使用位运算获取一个数的某一位 直接右移n位 再与1清除高位即可 Returns the Nth bit of X Assumes 0 lt N lt 31 unsigned get bit unsigned x unsigned n
  • 利用LVS实现Web服务器的负载均衡

    LVS介绍 LVS Linux Virtual Server 负载调度器 是全球最流行的四层负载均衡开源软件 由章文嵩博士 当前阿里云产品技术负责人 在1998年5月创立 可以实现Linux平台下的负载均衡 LVS集群类型中的术语 VS V
  • vue-cli入门(三)——人员管理实例

    前言 在开始开发实例前 应首先了解一下vue cli的项目结构 接着我们一起来实现一个小demo 人员管理 功能简单 通过这个实例让大家熟悉使用vue cli开发项目的一些操作 加深对vue cli项目结构的印象 http www jian
  • Linux 下杀毒软件 clamav 0.104.2 离线安装及测试(CentOS7)

    文章目录 Linux 下杀毒软件 clamav 0 104 2 离线安装及测试 CentOS7 1 下载安装 2 配置 3 运行 4 服务器配置 4 1 设置 daemon 守护进程 推荐 4 2 定时任务 5 ClamAV 常用命令 Li
  • SQL Lesson 8: 关于特殊关键字 NULLs

    SQL Lesson 8 关于特殊关键字 NULLs 在查询条件中处理 NULL 使用 在查询条件中处理 NULL SELECT column another column FROM mytable WHERE column IS IS N
  • 深度学习-LeCun、Bengio和Hinton的联合综述

    发表于 2015 06 01 07 10 8257次阅读 来源 Nature 17 条评论 作者 Yann LeCun Yoshua Bengio Geoffrey Hinton 深度学习 自然语言处理 计算机视觉 语音识别 geoffre
  • 跨平台原理:

    跨平台原理 Java中存在Java虚拟机 可以将JAVA程序翻译成对应平台可以执行的程序进行运行 Java程序可以一处编译 到处运行 即java编译时将 java文件转换为无关平台的字节码 class文件 而虚拟机将 class文件翻译给不
  • 分布式发布订阅消息系统—Apache Kafka

    1 什么是Kafka Kafka是一种高吞吐量的分布式发布订阅消息系统 它可以处理消费者规模的网站中的所有动作流数据 这种动作 网页浏览 搜索和其他用户的行动 是在现代网络上的许多社会功能的一个关键因素 这些数据通常是由于吞吐量的要求而通过
  • 基于ant design vue实现的多层菜单组件封装

    菜单组件 不同于树组件的是 树组件可以选很多个 而菜单组件只可以选择一个 这里放上我的源代码 current 是默认选择的节点 是一个数组current 5 3 1 默认选择的节点 openKeys是默认展开的节点 也是一个数组openKe
  • ajax无法发送json串,Ajax检索Json字符串,但无法将成功数据循环为对象

    我的项目是用d3 js绘制grahp 我发现了一些php代码 这绝对是我想要的 但我正在与C 和主场迎战所以我把它转换成asp net 首先 我想编写一些硬编码数据样本并使用d3 js绘制图像 以及该PHP项目的JavaScript代码 现
  • React Hook 之 useMemo及 React.memo

    一 useMemo const memoizedValue useMemo gt computeExpensiveValue a b a b 返回一个 memoized 值 把 创建 函数和依赖项数组作为参数传入 useMemo 它仅会在某