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. useRef 和 useState 的区别
| 对比项 | useRef | useState |
|---|---|---|
| 改值是否触发渲染 | 否 | 是 |
| 适合存什么 | 不参与视图的数据、DOM 引用 | 参与视图渲染的数据 |
| 典型用途 | DOM、实例、定时器、最新值缓存 | UI 状态 |
6. 面试高频答法
Q1:什么时候该用 useRef 而不是 useState?
当你需要“记住一个值”,但这个值变化不该让组件重新渲染时。
Q2:为什么它能保存跨 render 的值?
因为 React 会在组件生命周期内保留同一个 ref 对象引用。
Q3:useRef 能当全局变量吗?
不能。它的作用域仍然是当前组件实例。
常见追问
1)可以在 render 里直接修改 ref.current 吗?
技术上能,但通常不推荐在 render 阶段做带副作用的写入,除非是非常明确且安全的初始化模式。
2)createRef 和 useRef 有什么区别?
函数组件里通常用 useRef,因为它能在多次 render 之间保持同一个对象;createRef 更常见于类组件或某些特殊场景。
易错点/坑
- 用
useRef存页面要显示的数据,却期待 UI 自动更新。 - 把
ref当成响应式状态。 - 过度依赖 ref 隐藏真实数据流。
速记要点(可背诵)
useRef:跨 render 保存可变值,但改它不触发渲染。- 两大用途:拿 DOM / 实例;保存不参与渲染的数据。
- 页面要跟着变,就用 state,不要只用 ref。