React缓存,如何使用useAsyncMemo()缓存异步函数结果?
发布于 作者:苏南大叔 来源:程序如此灵动~

上一篇文章里面,苏南大叔说可以使用useMemo()
缓存普通函数的昂贵计算逻辑结果。在文章的最后,特别强调了useMemo()
作用于普通函数,而不能作用于异步函数。异步函数的关键词有:async
、await
、promise
、resolve
、reject
、.then()
等等。本文将使用react
的另外一个非官方钩子useAsyncMemo()
,实现异步函数结果的缓存。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
,use-async-memo@1.2.5
。useAsyncMemo()
是个钩子,所以只能用在函数式组件里面。
接口代码
异步函数大部分情况下是成功resolve()
,但是也存在reject()
或者new Error()
。在苏南大叔以前的文章里面,还分为setTimeout
模拟,以及fetch
真实请求两种情况。
对于本文实验用的接口来说,存在一个是否catch
异常的问题(reject
其实也算个异常):
- 在前面的文章里面,苏南大叔描述,不能
catch
,因为这个要由useRequest
钩子处理。 - 本篇文章里面,情况有变。这个新的
useAsyncMemo()
钩子,不能处理异常。所以,需要自行catch
。
本地代码
ApiService.js
:
远程代码
express.js
:
不使用useAsyncMemo
假设没有这个use-async-memo
的钩子的话,可能代码是这样写的:
现况之useeffeect

这里为了避免async
延时更新带来死循环。这里使用useEffect()
来保证其只执行一次。如果有依赖项的话,也可以添加到useEffect()
的第二个参数里面。
现况之死循环
不使用useEffect()
的话,可能会陷入死循环。虽然是个类似setInterval
的效果,并不是while(true)
那样的死循环。

useAsyncMemo()
useAsyncMemo()
是个非官方的钩子,它的github
地址是:
作者看上去是个阿里的神人。useAsyncMemo()
对标的就是react
官方的useMemo()
,所以两者的功用也很相似,就是对函数的结果进行缓存。useAsyncMemo()
缓存的是异步函数,useMemo()
缓存的是非异步函数。
官方给出的原型是这样的:
值得注意的是:这里出现了一个initial?
参数。这个参数是useMemo()
里面所没有的。经过代码尝试,发现这个参数是用来提供一个结果占位符的。换句话说,就是这个“昂贵的异步函数”还没有返回值的时候,提前先返回一个值。等异步函数正式返回数据之后,就代替这个占位的值。
使用之前,记得先安装use-async-memo
:
useAsyncMemo()之异步
这个useAsyncMemo()
的依赖项参数,必须填写,不能省略,否则就是死循环。即使没有依赖项,那么,也需要写成[]
。如果需要传递参数的话,依然需要做到:
- 参数取自全局(父级)
- 参数加入依赖项(参数变,函数就变)

useAsyncMemo()之默认值
useAsyncMemo()
存在第三个参数,就是这个函数的默认值,就是运算结果没返回的时候的占位值。

useAsyncMemo源码
如果查看useAsyncMemo
源码的话,就会发现:它的背后就是个useEffect()
。其TypeScript
的代码极其简单:
学习一下人家的代码思路,总归是极好的。
useAsyncMemo()更好的例子
这个例子比较具有实际意义,参考:

这段代码的理解上,就是useAsyncMemo()
会有个状态的变化过程,会再次引起组件渲染。
对应的接口服务:
相关文章
- https://newsn.net/say/js-promise.html
- https://newsn.net/say/js-request-get.html
- https://newsn.net/say/js-request-fake.html


