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

React中直接取useRef(...).current赋值是否属于反模式?

对 const refName = useRef(...).current 写法的分析

这种写法唯一的动机就是少写几次.current,没有任何实际优势,反而存在致命的逻辑缺陷,绝大多数场景下都会出bug。


核心弊端

  • 完全丢失ref的跨渲染同步能力
    useRef的本质是返回一个组件全生命周期内引用地址固定的对象,所有可变值都存在这个对象的current属性上,React更新DOM、修改存值时只会修改这个固定对象的current字段。如果在渲染阶段直接把current取出来赋值给普通变量,相当于拿到的是当前渲染节点上current值的快照:如果是原始类型值就是值拷贝,如果是引用类型就是当时的引用地址,后续ref.current的任何更新都不会同步到你提前取出来的这个变量上,完全丧失ref跨渲染周期存值的核心作用。
  • 根本无法正常更新ref存储的值
    如果你用const声明这个取出来的变量,后续想修改值时会直接抛出赋值错误;就算改成let声明,修改的也只是当前渲染闭包里的局部变量,组件下一次重渲染时,这个变量会被重新赋值为初始的useRef(xxx).current,之前的修改直接丢失,根本达不到持久化存储的效果。
  • 用来绑定DOM时100%拿不到目标节点
    组件首次执行渲染函数时真实DOM还没挂载,此时useRef(null).current拿到的就是null。等React完成DOM挂载、给ref的current属性赋值真实节点时,你之前存到变量里的null不会有任何更新,后续所有DOM操作都会因为拿到空值失效。

典型错误场景复现:

function BadComponent() {
  // 首次渲染就取出current,存初始值
  const timerRef = useRef(0).current;
  const domRef = useRef(null).current;

  useEffect(() => {
    // 直接报错:Assignment to constant variable
    timerRef = setInterval(() => console.log('tick'), 1000);
    // 永远输出null,拿不到button节点,因为传给ref属性的不是ref对象
    console.log(domRef);
    return () => clearInterval(timerRef)
  }, [])

  return <button ref={domRef}>点我</button>
}

唯一看似“能跑”的特殊场景

只有当你满足以下所有条件时,这种写法不会立刻出bug:

  1. 传入useRef的初始值是一个永远不需要修改的引用类型值(比如固定的工具函数、静态配置对象)
  2. 永远不会在后续逻辑中给这个ref的current属性重新赋值

但这种场景完全没必要用useRef,直接把常量定义在组件外部作为模块级变量即可,还能省去每次渲染调用useRef的开销。

如果真的觉得反复写.current麻烦,也不要用这种取巧的错误写法,老老实实使用标准的ref对象即可——.current本身就是明确的语义标记,提醒你这是一个不会触发重渲染的可变跨渲染值,反而能降低代码维护时的认知成本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 18:54:28