React的use(promise) 为什么会出现promise被重复执行的问题?

codesandbox demo

这个demo里面演示了 use的两种使用方式:

  1. 组件的props接受一个promise,然后在这个组件内部 use这个 promise. 对应Message这个组件
  2. 组件自身内部创建了一个promise,然后在组件内部 use这个promise . 对应ProductList 这个组件.

现象

ProductList这个组件中 productJson = use(productPromise); 这行代码 会导致 useMemo中的fetch products 疯狂执行发请求.而且从log日志来看 useMemo好像没有起到缓存的作用.
image.png

问题就是 为什么会这样?

阅读 715
3 个回答

可以尝试打包应用后再检查一下,如果没有出现上述问题,那么可能是因为:React的Function组件在调试模式下不会被缓存,而是会每次都重新执行渲染(但原有的Class组件则不会);这是我以前写React遇到的一个现象,主要就是开发和调试的表现存在不一致性,具体原因没有深究过。

从当前运行结果来看,内部promise的一直被重复调用,然后看文档(https://zh-hans.react.dev/reference/react/use)即可知道。

当使用 Promise 调用 use API 时,它会与 Suspense 和 错误边界 集成。当传递给 use 的 Promise 处于 pending 时,调用 use 的组件也会 挂起。如果调用 use 的组件被包装在 Suspense 边界内,将显示后备 UI。一旦 Promise 被解决,Suspense 后备方案将被使用 use API 返回的数据替换。如果传递给 use 的 Promise 被拒绝,将显示最近错误边界的后备 UI。

调用 use 的组件也会 挂起,挂起的意思就是等待这个 Promise 的状态改变后组件才真正的渲染。每次调用promise函数都相当于每次都是第一次渲染,所以 useMemo 的缓存是等于无效的,上面都是个人推断,但按照这个思路排查是没有什么大的出入的。具体测试可以写个数据 useRef,每次渲染都 push 一下 useMemo 返回的结果,然后打印该数组,可以发现数组的长度没变。


更新回答

首先,遇到问题,排查问题,从结论往前推并不代表对问题认识不对,这只是一种排查的方式。主要是依据思路然后去验证才是整体思路。我提供了一个思路,也说了验证方式。但你并没有去验证,或者你没说出来。按照你的说法,应该去看源码才对,我贴个人家的源码解析
React use源码解析

然后我验证了我的思路,整体渲染逻辑和我推测基本相符。第一次渲染是,遇到use的pending会停止渲染,直到状态改变才重新执行组件渲染,然后导致产生新的useMemo返回结果,所以useMemo失效。这是我上班抽时间回答的,时间有限。

提出问题希望别人来完整回答你,那得有时间有心情,但你似乎就依赖于别人的回答一样(对于我说的排查方式,验证方法无视),要送到嘴边喂到嘴里才行...

487ad6209d77da9865421db96d416606.png
注意右下角打印,如果直接渲染的话,那么ref的值会被打印为null,然后才是1,但是现在是直接打印为1,所以use的状态为penning的时候也会直接将组件挂起,等接口返回后才重新全部渲染,渲染又会导致useMemo去执行,导致一直刷新的问题

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏