You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

useMemo与useEffect在Ref依赖下的行为差异探究

为什么useMemo依赖ref时无法捕获ref.current的更新?

核心原因很直白:useRef返回的是同一个引用对象,useMemo和useEffect的依赖数组对比的是「引用是否变化」,而非ref.current的值。结合你的代码和React的渲染流程,具体拆解如下:

关键前提先理清

  • useRef创建的对象,在组件整个生命周期里引用完全不变——不管ref.current怎么改,这个对象本身的内存地址始终没变化。
  • React的渲染流程是:渲染阶段(执行组件函数、计算JSX)→ 提交阶段(更新DOM、给ref.current赋值)→ 执行useEffect这类副作用。

你的组件实际运行流程(开发环境Strict Mode下)

你能看到两次渲染日志,是因为React Strict Mode在开发环境会刻意重复渲染,用来检测不安全的副作用:

第一次渲染

  1. 执行组件函数,调用useRef()得到一个{current: undefined}的对象,就叫它refObj。
  2. 执行useMemo:依赖数组是[refObj],此时ref.current还是undefined,所以输出memo ref undefined。
  3. 渲染阶段结束,进入提交阶段:React把<div>元素赋值给refObj.current。
  4. 执行useEffect:此时ref.current已经是DOM元素,输出effect ref {current: div}。
  5. Strict Mode触发effect清理,然后重新触发组件渲染(第二次渲染)。

第二次渲染

  1. 再次执行组件函数,调用useRef()返回的还是之前的refObj(引用完全一致)。
  2. 执行useMemo:依赖数组[refObj]和上一次没变化,哪怕Strict Mode下会重新执行useMemo,此时还处于渲染阶段,ref.current还没被重新赋值(提交阶段才会处理ref),所以依然输出memo ref undefined。
  3. 渲染阶段结束,提交阶段再次把<div>赋值给refObj.current。
  4. 执行useEffect:再次输出effect ref {current: div}。

为什么useEffect能拿到最新的ref.current?

useEffect是在提交阶段之后才执行的,这时候React已经完成了DOM更新和ref赋值,所以每次effect执行都能拿到最新的ref.current值。哪怕依赖数组里的ref引用没变化,Strict Mode下也会重复执行effect,所以你看到两次div的日志。

为什么useMemo拿不到?

useMemo是在渲染阶段执行的,这时候ref.current还没被赋值(要等提交阶段才会处理)。而且因为ref的引用自始至终没变化,依赖数组不会触发useMemo重新计算——就算Strict Mode下重复渲染,useMemo执行时ref.current依然是undefined。

简单总结:

  • useMemo在渲染时运行,此时ref还未绑定DOM;加上ref引用不变,不会触发重新计算。
  • useEffect在渲染完成后运行,此时ref已经绑定DOM,自然能拿到最新值。

内容的提问来源于stack exchange,提问作者machineghost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:54:55