你应该仅仅把useMemo作为性能优化的手段

在这里插入图片描述

文章概叙

本文主要通过几个简单的例子,讲解下useMemo这个hook,给诸君参考,也是给我自己做一个记录

关于useMemo

useMemo是一个React Hook,它在每次重新渲染的时候能够缓存计算的结果。

相比于其他很常用的hook,如useState、useEffect等hook,useMemo算是一个冷门的hook了,当然这必须有useCallback的一份大功劳,至少在我开发的项目中,很少直接使用useMemo,都是使
用useCallback来达成缓存组件的目的,不过这不能说useMemo是一个"过渡性"的东西。

但是无论如何,官网上有一句话我很喜欢,必须贴上来

你应该仅仅把 useMemo 作为性能优化的手段。如果没有它,你的代码就不能正常工作,那么请先找到潜在的问题并修复它。然后再添加
useMemo 以提高性能。

昂贵的计算开销

昂贵的计算开销,在我们开发中的生涯中,首当其冲就是遍历数组了,尤其是遍历一个几千个元素的数组,那可真是跟在LeetCode上做优化一样刺激。。

而useMemo的一个大优点,就是帮助我们跳过昂贵的计算开销,下面的例子会通过一个最简单的SKU来模拟如何使用useMemo。

useMemo语法

使用前,先让我们了解下useMemo的语法先。

useMemo(calculateValue, dependencies)
  • calculateValue

一个纯函数,可以返回任意类型,当我们的组件首次渲染的时候会调用该函数,在后续的渲染中,如果他的dependencies没有变化的时候,React将返回相同的值,否则会计算返回最新结果。

  • dependencies

依赖项,决定函数是否会被执行,是一个可为空的数组,从props、state中拿来用都ok,但是需要知道React会使用Object.js比较参数前后值是否一致。

  • return

在初次渲染时,useMemo 返回不带参数调用 calculateValue 的结果。
否则,根据依赖项是否变动决定是否返回缓存值或者重新计算值。

具体用法如下:

  const total = useMemo(() => {
    return count1 * 10 + count2 * 20;
  }, [count1, count2]);

Demo

首先,来一个最简单的SKU例子。

import {  useState } from "react";export default () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);
​
  console.log("渲染页面的次数");
  return (
    <>
      <div>
        <span>商品1:</span>
        <input
          placeholder="商品1的数量"
          defaultValue={count1}
          onBlur={(v: any) => {
            setCount1(v.target.value);
          }}
        />
        <div>商品1的价格为10</div>
      </div>
      <div>
        <span>商品2:</span>
        <input
          placeholder="商品2的数量"
          defaultValue={count2}
          onBlur={(v: any) => {
            setCount2(v.target.value);
          }}
        />
        <div>商品2的价格为20</div>
      </div>
      <div style={{ marginTop: "30px" }}>
        总价为:{count1 * 10 + count2 * 20}</div>
    </>
  );
};


UI如下:

在这里插入图片描述

在页面中,当我们输入框的onBlur事件触发时,我们会去计算一下价钱(当然实际上我们的价格计算不会放在前端去计算,因为安全问题以及优惠卷、商品剩余数量等问题,我们可以放在后台去计算)

秉承着能抽成一个方法就觉得不写成一个变量的原则,我们现在可以将其抽成一个计算价格的函数。

  const calcPrice = () => {
    return count1 * 10 + count2 * 20;
  };
  <div style={{ marginTop: "30px" }}>
  总价为:{calcPrice()}</div>

现在我们将计算价格的方法抽出来了,任务算是完成了,但是我们发现,我们价格的依赖项是count1以及count2,而由于存在用户不会改变数量的情况,所以我们可以用useMemo缓存下价格,即下面的代码:

  const calcPrice = useMemo(() => {
    return count1 * 10 + count2 * 20;
  }, [count1, count2]);
  
  //   const calcPrice = () => {
  //     return count1 * 10 + count2 * 20;
  //   };

但是需要注意,我们使用calcPrice的时候,不能直接调用跟这个方法了,因为他是一个高阶函数,所以要这么用

  <div>总价为:{calcPrice}</div>

至此,只有当我们的count1跟count2变化的时候,我们的价格才会重新计算一次,而useMemo的语法也算是被我们掌握了~

与useEffect的区别

做多了React开发的各位大佬,肯定也发现了useEffect以及useMemo有一个共同点,都是一个副作用函数,都是根据一个依赖项去执行某个操作。

useEffect以及useMemo还有两个区别。

  • 返回值

useEffect没有返回值,useEffect的本意是根据监听值的变化来重新执行副作用操作。
useMemo是在每次重新渲染的时候可以缓存计算的结果,所以需要将结果返回出去。

  • 触发时机

useMemo是在Dom更新之前触发,直接计算了结果。
useEffect是在Dom更新之后触发,在dom更新之后再次执行某些副作用操作。

如下面例子。当我们用useEffect计算价格时候,我们会这么做。

   const [total, setTotal] = useState(0);
   
  useEffect(() => {
    setTotal(count1 * 10 + count2 * 20);
  }, [count1, count2]);

在使用useEffect的时候,我们监听到count1以及count2变化了(请注意,此时是页面的第一次更新)

接着,我们就使用了setState函数,重新去将计算的结果渲染在了页面上(此前为第二次的渲染)

而当我们使用了useMemo的时候,由于是直接将返回的结果设置在页面上,所以当我们需要计算价格的时候,我们只是调用了一次。

在测试代码时,建议只保留一个商品,这样子能更加明显的看出来。

跳过组件的重新渲染

在上述的例子中,我们使用了useMemo来缓存总价,但是也只是缓存了一个计算好的数字而已,看起来并不酷炫,所以我们一般不会做这么Low的事情,我们会选择将整个显示价格的组件缓存下来。
在实际开发中,我们就经常会这么做,原因无他,即然显示价格的div中变动的因素只有一个价格,那你为啥不整个组件一起缓存呢…代码看起来还好看点。

而上述的缓存组件的说法,我们一般都成为跳过组件的重新渲染,与memo有异曲同工之妙。
最终代码如下

import { useEffect, useMemo, useState } from "react";export default () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);const totalComponent = useMemo(
    () => (
      <div style={{ marginTop: "30px" }}>
        总价为:{count1 * 10 + count2 * 20}</div>
    ),
    [count1, count2]
  );
  console.log("渲染页面的次数");
  return (
    <>
      <div>
        <span>商品1:</span>
        <input
          placeholder="商品1的数量"
          defaultValue={count1}
          onBlur={(v: any) => {
            setCount1(v.target.value);
          }}
        />
        <div>商品1的价格为10</div>
      </div>
      <div>
        <span>商品2:</span>
        <input
          placeholder="商品2的数量"
          defaultValue={count2}
          onBlur={(v: any) => {
            setCount2(v.target.value);
          }}
        />
        <div>商品2的价格为20</div>
      </div>
      {totalComponent}
    </>
  );
};

总结

文章的最后,本来是想演示下当我们的依赖项中含有一个数组的时候,我们的useMemo会不会因为对象或者数组的引用地址变动了而无法缓存,但是考虑到这种实际情况比较少(在memo中发生的概率大),所以就不写了,等大家遇到了再说。

你应该仅仅把useMemo作为性能优化的手段​

个人公众号,求大佬们关注~
在这里插入图片描述

公众号文章

预祝大家新年快乐

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

父元素flex:1 高度却被子元素撑开的问题

问题 当父元素设置了flex: 1; 的情况下&#xff0c;想在其中子元素超出父元素高度的情况下&#xff0c;产生滚动条&#xff0c;在父元素区域滚动。由于子元素高度不固定&#xff0c;故父元素设置为display: flex; flex-direction: column; 子元素设置flex: 1; overflow: auto;…

MySQL事务和SQL优化

目录 1 什么是事务 2 事务的特征 3 MySQL使用事务 实现 示例 4 事务的隔离级别 幻读 解决方法 脏读 不可重复读 幻读和不可重复读两者区别 事物的隔离级别 5 数据库优化 5.1 影响性能因素的优化 服务优化 应用优化 5.2 谁参与优化 5.3 系统优化 软件优化 硬件优…

落地PC ,AI的“iPhone时刻”要来了?

在AI技术浪潮持续翻涌的背景下&#xff0c;近段时间&#xff0c;不断有声音强调“2024年将是AIPC元年”。 为了奔赴这一可以预见的未来&#xff0c;产业链上下游的企业也“干劲十足”。品牌商方面&#xff0c;2024年的国际消费电子展&#xff08;CES&#xff09;上&#xff0c…

贪吃蛇项目

引言&#xff1a; 本文章使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇。 实现基本功能&#xff1a; 1.贪吃蛇地图绘制。 2.蛇吃食物的功能&#xff08;上、下、左、右方向键控制蛇的动作&#xff09; 3.蛇撞墙死亡 4.蛇咬到自己死亡 5.计算得分 6.蛇加速…

基于springboot原创歌曲分享平台源码和论文

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理平台应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

Coppeliasim倒立摆demo

首先需要将使用Python远程控制的文件导入到文件夹&#xff0c;核心是深蓝色的三个文件。 本版本为4.70&#xff0c;其文件所在位置如下图所示&#xff0c;需要注意的是&#xff0c;目前不支持Ubuntu22的远程api&#xff1a; 双击Sphere这一行的灰色文件&#xff0c;可以看到远程…

UE5/UE4中3D汉字字体文字的创建与实现

本案例工程下载位置&#xff1a;https://mbd.pub/o/bread/ZZqVmJ9v 在虚幻引擎5&#xff08;UE5&#xff09;和虚幻引擎4&#xff08;UE4&#xff09;中&#xff0c;实现3D汉字字体的创建是一项常见的需求。 本文将详细介绍两种有效的方法&#xff1a; 1.通过TextRender配合Of…

Ubuntu系统安装 Redis

环境准备 Ubuntu 系统版本&#xff1a;22.04.3Redis 版本&#xff1a;6.2.12 检查本地 make 环境 make -version若没有安装&#xff0c;则需要安装 sudo apt install make检查本地 gcc 环境 gcc -version若没有安装&#xff0c;则需要安装 sudo apt install gcc。 sudo a…

第32关 k8s集群管理开源神器 - k9s

------> 课程视频同步分享在今日头条和B站 大家好&#xff0c;我是博哥爱运维。 随着我们管理维护的K8S集群上线&#xff0c;怎么管理好集群上面成百上千的服务pod&#xff0c;就是我们该操心的事情了。这里博哥把在生产中一直在用的一个开源管理工具k8s&#xff0c;github…

C++数据结构与算法——数组

C第二阶段——数据结构和算法&#xff0c;之前学过一点点数据结构&#xff0c;当时是基于Python来学习的&#xff0c;现在基于C查漏补缺&#xff0c;尤其是树的部分。这一部分计划一个月&#xff0c;主要利用代码随想录来学习&#xff0c;刷题使用力扣网站&#xff0c;不定时更…

Facebook的创新征程:社交媒体的演进之路

在当今数字化时代&#xff0c;社交媒体已经成为人们生活中不可或缺的一部分&#xff0c;而Facebook作为社交媒体领域的巨头&#xff0c;一直在不断创新和演进。本文将深入探讨Facebook的创新征程&#xff0c;追溯其社交媒体的发展历程&#xff0c;探讨其对用户、社会和数字时代…

hcip---ospf综合实验

一&#xff1a;实验要求 1、R4为ISP&#xff0c;其上只能配置IP地址&#xff0c;R4与其所有直连设备间均使用公有IP 2、R3-R5/6/7为MGRE环境&#xff0c;R3为中心站点 3、整个OSPF环境IP基于R4的环回 4、所有设备均可访问R4的环回 5、减少LSA的更新量&#xff0c;加快收敛…

基础算法(二)

一 高精度计算 int能表示范围为2^32&#xff0c;这看起来很大&#xff0c;但在大数据时代的如今&#xff0c;不说是int 哪怕是long long也是不够的&#xff0c;那么为了使用或计算这些超出或远超整形大小的数&#xff0c;我们这些数的计算方法称为高精度计算。 &#xff08;1)…

视频转GIF软件,轻松制作GIF动图

我们每天都会接触到大量的视频内容&#xff0c;从社交媒体到新闻网站&#xff0c;从电影到短视频。但你是否想过&#xff0c;如何将那些或是令人捧腹大笑或是让人感动至深的瞬间&#xff0c;轻松的保存下来随时回味&#xff1f;答案就是——将视频转为GIF动图。相较于传统的视频…

共享的IP隔一段时间就变?用这种方法可以不需要知道电脑IP

前言 一般来说,电脑接入路由器之后,IP是由路由器自动分配的(DHCP),但如果隔一段时间不开机连接路由器,或者更换了别的网卡进行连接,自动分配的IP就会更改。 比如你手机连接着电脑的共享IP:192.168.1.10,但过段时间之后,电脑的IP突然变成了192.168.1.11,那么你的所有…

假期刷题打卡--Day18

1、MT1168阶乘数 输入正整数N&#xff0c;找出它是否是一个等于其他数的阶乘值的数&#xff0c;输出YES或者NO。 格式 输入格式&#xff1a; 输入正整数N 输出格式&#xff1a; 输出YES或者NO 样例 1 输入&#xff1a; 5输出&#xff1a; NO 相关知识点 阶乘 可以理…

[Tcpdump] 网络抓包工具使用教程

往期回顾 海思 tcpdump 移植开发详解海思 tcpdump 移植开发详解 前言 上一节&#xff0c;我们已经讲解了在海思平台如何基于静态库生成 tcpdump 工具&#xff0c;本节将作为上一节的拓展内容。 一、tcpdump 简介 「 tcpdump 」是一款强大的网络抓包工具&#xff0c;它基于…

petalinux2022.2启动文件编译配置

安装必要运行库: sudo apt-get install iproute2 gawk python3 python sudo apt-get install build-essential gcc git make net-tools libncurses5-dev tftpd sudo apt-get install zlib1g-dev libssl-dev flex bison libselinux1 gnupg wget git-core diffstat sudo apt-ge…

Lucene 查询原理

Lucene 查询原理 - 知乎 前言 Lucene 是一个基于 Java 的全文信息检索工具包&#xff0c;目前主流的搜索系统Elasticsearch和solr都是基于lucene的索引和搜索能力进行。想要理解搜索系统的实现原理&#xff0c;就需要深入lucene这一层&#xff0c;看看lucene是如何存储需要检…

kafka集群搭建需要做的事情

首先&#xff0c;虚拟机克隆好之后的步骤如下&#xff1a; 1. 修改IP、主机名&#xff0c;关闭防火墙&#xff1b;&#xff08;reboot重启&#xff09; 2. 在/etc/hosts文件中进行IP与主机名的映射配置&#xff0c;集群中每天都记得配置&#xff1b; 3. 安装JDK并进行分发&a…