使用use-callback-ref的useCallbackRef时,依赖其.current的useEffect为何触发两次
原因分析
这个现象是use-callback-ref的内部实现逻辑和React的useEffect依赖检测规则共同导致的,具体执行流程如下:
- 原生React的ref更新不会触发组件重渲染,因此把
ref.current放在useEffect依赖里时,只有组件首次渲染会执行一次useEffect,后续current变更不会触发。而useCallbackRef为了实现「ref变更时触发自定义回调」的能力,内部会通过状态更新驱动组件重渲染,保证回调逻辑能正常执行。 - 组件首次渲染时,
divCbRef.current初始值为null,此时useEffect执行会被你的非空判断拦截,不会触发计数,和你观测到的「null阶段不触发」的现象一致。 - DOM挂载完成后,React首先给
divCbRef.current赋值为真实DOM节点,随后useCallbackRef触发你传入的自定义回调(setUseCbRefCounter逻辑),触发组件第一次重渲染。 - 第一次重渲染完成后,React对比useEffect依赖,发现
divCbRef.current从null变成了DOM节点,第一次执行内部计数逻辑,useCbRefEffectCounter变为1。 - 为了兼容React并发渲染特性,
useCallbackRef会在重渲染后再做一次ref值同步操作,这个操作会被React的依赖检测判定为divCbRef.current发生了变更,因此会第二次执行useEffect,useCbRefEffectCounter变为2,最终呈现出触发两次的现象。
解决方案
有两种方案可以规避这个问题:
- 优先使用
useCallbackRef的第二个参数回调处理ref挂载后的逻辑,这个回调只会在ref真实变更时触发一次,完全符合预期。 - 如果一定要用useEffect实现相关逻辑,可以把
useCbRefCounter作为useEffect的依赖,这个状态只会在ref挂载时变更一次,不会出现重复触发的问题。
内容的提问来源于stack exchange,提问作者Raz Luvaton
相关产品推荐
相关产品推荐

