React缓存,useMemo如何缓存函数结果?普通函数昂贵结果
发布于 作者:苏南大叔 来源:程序如此灵动~React
缓存的另外一个分支,就是使用useMemo()
钩子缓存函数运行结果。之所以缓存这个函数结果,是因为对应的函数的运算比较复杂,比较浪费算力。出于节约算力的目的,设定这个函数输入一致的时候,输出必然一致。可以使用这个useMemo()
钩子来缓存对应的结果。当然,这句话别较真,什么时候该缓存这个运算结果,看实际情况而定。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
。useMemo()
是个钩子,所以只能用在函数式组件里面。
useMemo()钩子
use
开头的react
函数,都是钩子,都只能用于函数式组件里面,传统的类组件写法里面不能使用。它的目标作用对象是个被执行的函数,输出是对应函数的运算结果。主打的是:不用再次运算,节约算力。
当依赖项变化的时候,这个被缓存的运算结果失效,需要再次运算。理论上来说,这个被缓存的计算结果,应该是个比较消耗算力的“昂贵函数”。
需要特别说明的是:这个useMemo()
的目标函数,需要是个普通的函数,并不支持async
异步相关函数。也就是说和promise
、await
、async
、setTimeout
等字样都是无缘的。
下面的代码中,需要知晓一个前提:执行useState()
的导出函数,必定会引起所在组件的更新渲染。苏南大叔通过执行更改state
的函数,观察对应被useMemo
的函数是否执行了console.log()
即可。
普通写法,依赖项
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()
的第一个参数是个函数定义,并不是个函数执行。这样的话,给这个函数传递参数就成了一个特大问题。
苏南大叔参考了一下网上大家的意见,解决方案写法很多。但是,思路基本上都是,想办法把要传递的参数挂在父层。并且把参数都设置为依赖项。这样的话,虽然看起来写法很怪异。但是,也确实达到了被缓存函数的参数效果。
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>
);
}
本段代码中,昂贵运算值e2
和e3
的运算逻辑所需要的参数,都是来自于父层的变量,并且对应的变量都添加到了依赖项。然而实际的依赖项,params
来自setState()
的导出值【每次渲染保持不变】,params2
是组件内部定义的值【每次渲染都会变化】。
相关文章
这个useMemo()
钩子,不支持对async
函数进行缓存。所以,才有标题中的“作用于普通函数”。
- https://newsn.net/say/react-usememo.html
- https://newsn.net/say/react-memo.html
- https://newsn.net/say/react-memo-2.html
- https://newsn.net/say/react-memo-3.html
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。