我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

React缓存的另外一个分支,就是使用useMemo()钩子缓存函数运行结果。之所以缓存这个函数结果,是因为对应的函数的运算比较复杂,比较浪费算力。出于节约算力的目的,设定这个函数输入一致的时候,输出必然一致。可以使用这个useMemo()钩子来缓存对应的结果。当然,这句话别较真,什么时候该缓存这个运算结果,看实际情况而定。

苏南大叔:React缓存,useMemo如何缓存函数结果?普通函数昂贵结果 - usememo缓存普通函数结果
React缓存,useMemo如何缓存函数结果?普通函数昂贵结果(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1useMemo()是个钩子,所以只能用在函数式组件里面。

useMemo()钩子

use开头的react函数,都是钩子,都只能用于函数式组件里面,传统的类组件写法里面不能使用。它的目标作用对象是个被执行的函数,输出是对应函数的运算结果。主打的是:不用再次运算,节约算力。

当依赖项变化的时候,这个被缓存的运算结果失效,需要再次运算。理论上来说,这个被缓存的计算结果,应该是个比较消耗算力的“昂贵函数”。

需要特别说明的是:这个useMemo()的目标函数,需要是个普通的函数,并不支持async异步相关函数。也就是说和promiseawaitasyncsetTimeout等字样都是无缘的。

下面的代码中,需要知晓一个前提:执行useState()的导出函数,必定会引起所在组件的更新渲染。苏南大叔通过执行更改state的函数,观察对应被useMemo的函数是否执行了console.log()即可。

普通写法,依赖项

苏南大叔:React缓存,useMemo如何缓存函数结果?普通函数昂贵结果 - 昂贵运算值e0
React缓存,useMemo如何缓存函数结果?普通函数昂贵结果(图3-2)

import React, { useMemo,useState } from "react";
export default function App() {
  const [a, setA] = useState(1);
  const e0 = useMemo(() => {
    console.log("昂贵运算值 e0");
    return 1 * 2 * 3 + Math.random().toFixed(2);
  });

  const e1 = useMemo(() => {
    console.log("昂贵运算值 e1");
    return 1 * 2 * 3 + Math.random().toFixed(2);
  }, []);
  return (
    <div>
      <div>
        {e0},,,{e1}
      </div>
      <button onClick={() => setA(a + 1)}>组件渲染,观察昂贵值是否变化</button>
    </div>
  );
}

这个例子,就是说明useMemo()的第二个参数,依赖项的作用的。这个例子中,

  • 昂贵运算值e0,因为没有传递依赖参数,导致useMemo()形同虚设,仅仅相当于函数执行()
  • 而昂贵运算值e1,传递了依赖项[],明确表示自己什么也不依赖。形成了恒定缓存的语义结果。

特殊写法,传参

useMemo()的第一个参数是个函数定义,并不是个函数执行。这样的话,给这个函数传递参数就成了一个特大问题。
苏南大叔参考了一下网上大家的意见,解决方案写法很多。但是,思路基本上都是,想办法把要传递的参数挂在父层。并且把参数都设置为依赖项。这样的话,虽然看起来写法很怪异。但是,也确实达到了被缓存函数的参数效果。

苏南大叔:React缓存,useMemo如何缓存函数结果?普通函数昂贵结果 - 昂贵运算值e3
React缓存,useMemo如何缓存函数结果?普通函数昂贵结果(图3-3)

import React, { useMemo, useState } from "react";
export default function App() {
  const [a, setA] = useState(1);
  const [params, setParams] = useState([3, 4, 5]);
  const e2 = useMemo(() => {
    console.log("昂贵运算值 e2");
    return params[0] * params[1] * params[2] + Math.random().toFixed(2);
  }, [params]);
  const params2 = [3, 4, 5];
  const e3 = useMemo(() => {
    console.log("昂贵运算值 e3");
    return params2[0] * params2[1] * params2[2] + Math.random().toFixed(2);
  }, [params2]);
  return (
    <div>
      <div>
        {e2},,,{e3}
      </div>
      <button onClick={() => setA(a + 1)}>组件渲染,观察昂贵值是否变化</button>
    </div>
  );
}

本段代码中,昂贵运算值e2e3的运算逻辑所需要的参数,都是来自于父层的变量,并且对应的变量都添加到了依赖项。然而实际的依赖项,params来自setState()的导出值【每次渲染保持不变】,params2是组件内部定义的值【每次渲染都会变化】。

相关文章

这个useMemo()钩子,不支持对async函数进行缓存。所以,才有标题中的“作用于普通函数”。

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react