跳到主要内容

useRef

面试速答(30 秒版 TL;DR)

  • useRef 返回一个形如 { current: ... } 的可变对象,并且这个对象在组件整个生命周期内通常保持同一引用。
  • ref.current 不会触发重新渲染,这是它和 useState 最大的区别。
  • 常见用途有两类:
    • 拿 DOM / 组件实例引用
    • 保存跨渲染周期但不需要触发视图更新的数据
  • 面试里一定要说:useRef 不是响应式状态容器。

1. 心智模型

组件每次 render 都会重新执行,但有些值我们希望:

  • 跨 render 保留
  • 修改时不引发 UI 更新

这时就适合放到 useRef

const countRef = useRef(0)
countRef.current += 1

这会更新内存里的值,但不会触发重新渲染。

2. 两类最常见用途

2.1 获取 DOM

const inputRef = useRef<HTMLInputElement>(null)

useEffect(() => {
inputRef.current?.focus()
}, [])

2.2 存放不参与渲染的数据

例如:

  • 定时器 id
  • 上一次的值
  • 第三方实例
  • 防抖节流句柄

3. 为什么它不会触发渲染

因为 React 不会跟踪 ref.current 的变化来决定 UI 更新。

这正是它的价值所在:

  • 能持久保存值
  • 又不会引发额外 render

但也意味着:如果页面要显示这个值,就不该只放 ref

4. React 18 里它常用来解决什么问题

4.1 闭包旧值辅助方案

在某些异步回调里,useRef 常被用来保存最新值,避免拿到旧闭包。

4.2 桥接外部系统

例如:

  • 图表实例
  • 视频播放器实例
  • WebSocket 实例

这类对象本来就不适合放进 state。

5. useRefuseState 的区别

对比项useRefuseState
改值是否触发渲染
适合存什么不参与视图的数据、DOM 引用参与视图渲染的数据
典型用途DOM、实例、定时器、最新值缓存UI 状态

6. 面试高频答法

Q1:什么时候该用 useRef 而不是 useState

当你需要“记住一个值”,但这个值变化不该让组件重新渲染时。

Q2:为什么它能保存跨 render 的值?

因为 React 会在组件生命周期内保留同一个 ref 对象引用。

Q3:useRef 能当全局变量吗?

不能。它的作用域仍然是当前组件实例。

常见追问

1)可以在 render 里直接修改 ref.current 吗?

技术上能,但通常不推荐在 render 阶段做带副作用的写入,除非是非常明确且安全的初始化模式。

2)createRefuseRef 有什么区别?

函数组件里通常用 useRef,因为它能在多次 render 之间保持同一个对象;createRef 更常见于类组件或某些特殊场景。

易错点/坑

  • useRef 存页面要显示的数据,却期待 UI 自动更新。
  • ref 当成响应式状态。
  • 过度依赖 ref 隐藏真实数据流。

速记要点(可背诵)

  • useRef:跨 render 保存可变值,但改它不触发渲染。
  • 两大用途:拿 DOM / 实例;保存不参与渲染的数据。
  • 页面要跟着变,就用 state,不要只用 ref。