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

news2024/9/22 21:33:28

在这里插入图片描述

文章概叙

本文主要通过几个简单的例子,讲解下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作为性能优化的手段​

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

公众号文章

预祝大家新年快乐

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

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

相关文章

LPC804开发(7.SPI使用)

1.前言 原本说写ADC&#xff0c;但是考虑到6已经给了串口&#xff0c;算了算了&#xff0c;还是把SPI和IIC放到7和8吧。整体用下来感觉NXP的协议比ST和TI开发的完善的&#xff0c;都可以走硬件&#xff0c;比较完善的底层开发&#xff0c;没有硬伤&#xff0c;那么接下来我们来…

教你一招轻松把模糊的照片变高清

亲爱的朋友们&#xff0c;你们是否也曾经遇到过这样的问题——精心拍摄的照片或珍藏已久的图片突然变得模糊不清&#xff0c;让人心情郁闷&#xff1f;别担心&#xff0c;我发现了解决这个问题的秘诀&#xff01;借助一些专业的图片修复工具&#xff0c;那些模糊的瞬间可以重新…

react实现滚动到顶部组件

新建ScrollToTop.js import React, { useState, useEffect } from react; import ./ScrollToTop.css;function ScrollToTop() {const [isVisible, setIsVisible] useState(true);// Show button when page is scorlled upto given distanceconst toggleVisibility () > {…

一分钟在SpringBoot项目中使用EMQ

先展示最终的结果: 生产者端: RestController RequiredArgsConstructor public class TestController {private final MqttProducer mqttProducer;GetMapping("/test")public String test() {User build User.builder().age(100).sex(1).address("世界潍坊渤…

Wireshark网络协议分析 - UDP协议

在我的博客阅读本文 文章目录 1. 基础2. 实战2.1. 用Go写一个简单的UDP服务器与客户端2.2. Wireshark抓包分析 3. UDP与TCP的区别4. 参考资料 1. 基础 UDP包的数据结构&#xff1a; 2. 实战 2.1. 用Go写一个简单的UDP服务器与客户端 我们这里使用Golang写了一个简单的9830端…

docker由浅入深

一、什么是docker docker 顾名思义就是轮船的意思&#xff0c;轮船我们知道是通过集装箱运载货物的东西&#xff0c;那么docker其实也是类似的东西&#xff0c;只是装载的是虚拟的运行程序罢了。其中集装箱在docker里面被称为container&#xff08;后面以容器称之&#xff09;…

林浩然的Python奇遇记:从小白到科学界的编程魔法师

林浩然的Python奇遇记&#xff1a;从小白到科学界的编程魔法师 Lin Haoran’s Python Adventure: From Novice to Programming Sorcerer in the Scientific Realm 在那个平凡的午后&#xff0c;我们的主角林浩然——一个对编程一窍不通但对世界充满好奇的物理学大二学生&#x…

qiankun子应用静态资源404问题有效解决(遇到了http请求静态文件404、css文件引用图片无法显示、svg图片转换成 base64无法显示等问题)

在&#x1f449;&#x1f3fb; qiankun微前端部署&#x1f448;&#x1f3fb;这个部署方式的前提下&#xff0c;遇到的问题并解决问题的过程 >> 问题现象 通过http请求本地的静态json文件404 css中部分引入的图片无法显示 >> 最开始的解决方式 在&#x1f449;…

Linux第36步_创建正点原子的TF-A工作区

创建正点原子的TF-A工作区&#xff0c;目的是想查看正点原子的设备树文件“stm32mp157d-atk.dts”和设备树头文件“stm32mp157d-atk.dtsi”&#xff0c;了解设备树是什么样子&#xff0c;为后期基于“ST公司的源码”创建自己的设备树提供参考&#xff0c;同时也是为了学习移植u…

飞桨大模型分布式训练技术

今天我为大家介绍飞桨大模型分布式训练技术&#xff0c;内容分为以下几个部分&#xff1a; 首先&#xff0c;我会介绍大模型训练面临的重点难题&#xff1b;然后&#xff0c;为大家介绍飞桨在大模型训练领域的特色分布式训练技术和优化方案&#xff1b;最后&#xff0c;伴随着…

NeRF:神经辐射场复杂场景的新视图合成技术

NeRF&#xff1a;神经辐射场复杂场景的新视图合成技术 NeRF&#xff1a;神经辐射场复杂场景的新视图合成技术项目背景与意义如何运行&#xff1f;快速开始更多数据集 预训练模型方法与实现结语服务 NeRF&#xff1a;神经辐射场复杂场景的新视图合成技术 在计算机视觉领域&…

工业物联网网关如何实现工业设备的远程运维?-天拓四方

随着工业4.0和智能制造的快速发展&#xff0c;工业设备的远程运维已经成为提高企业生产效率和降低运营成本的重要手段。工业物联网网关作为这一过程中的关键组件&#xff0c;发挥着不可或缺的作用。本文将重点探讨工业物联网网关如何实现工业设备的远程运维&#xff0c;并结合实…

网络和Linux网络_15(IO多路转接)reactor编程_服务器+相关笔试题

目录 1. reactor的服务器 1.1 Sock.hpp 1.2 加协议分割报文 1.3 序列化和反序列化 Protocol.hpp main.cc Epoll.hpp TcpServer.hpp 2. 相关笔试题 答案及解析 本篇完。 1. reactor的服务器 Log.hpp和以前一样&#xff0c;因为下面要写ET模式所以Sock.hpp加了一个把…

[Python] 什么是集成算法,什么是随机森林?随机森林分类器(RandomForestClassifier)及其使用案例

什么是集成算法&#xff1f; 集成算法是一种机器学习方法&#xff0c;它将多个基本的学习算法&#xff08;也称为弱学习器&#xff09;组合在一起&#xff0c;形成一个更强大的预测模型。集成算法通过对基本模型的预测进行加权平均或多数投票等方式&#xff0c;来产生最终的预…

【Leetcode】两数之和

目录 题目&#xff1a; 解法1&#xff1a;暴力双for 1.想到的第一种方法两for循环解 复杂度分析 解法2&#xff1a;hash表 总结&#xff1a; 笔记&#xff1a; 题目&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标…

简单区间DP

文章目录 什么是区间DpAcWing 282. 石子合并题意分析思路解析状态表示状态计算 CODE需要注意的问题 什么是区间Dp 区间Dp指的是某些问题可以用区间来划分解决。 AcWing 282. 石子合并 题目链接&#xff1a;穿梭时间的画面的钟 题意分析 从一排石子中选择相邻的两堆进行合并…

2024-01-25 力扣高频SQL50题目1193每月交易

1.1193每月交易 1 count可以这样用。。 COUNT(IF(state approved, 1, NULL)) AS approved_count 如果 COUNT(if(state approved,1,0))&#xff0c;这里变成0&#xff0c;就不对了。因为count计数时候&#xff0c;只要里面不是null&#xff0c;就会算进去。 sum(if(state …

(学习日记)2024.01.27

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

行为型设计模式—迭代器模式

迭代器模式&#xff1a;也叫作游标模式&#xff0c;能在不暴露复杂数据结构内部细节的情况下遍历其中所有的元素。在迭代器的帮助下&#xff0c; 客户端可以用一个迭代器接口以相似的方式遍历不同集合中的元素。 当集合背后为复杂的数据结构&#xff0c;且希望对客户端隐藏其复…

漏洞原理文件上传漏洞

一 文件上传漏洞介绍&#xff08;理论&#xff09; 文件上传漏洞是一种常见的web应用程序漏洞&#xff0c;允许攻击者向服务器上传恶意文件。这种漏洞可在没有恰当的安全措施的情况下&#xff0c;将任意类型的文件上传到服务器上&#xff0c;从而可能导致以下安全问题&#xff…