React useRef

React 中用于保存不参与渲染的可变值,或引用 DOM 节点的 Hook。

#tech / dev / frame #resource / react #type / concept #status / growing

[!info] related notes

React useRef

useRef 用于保存一个在组件多次渲染之间持续存在、但变化后不会触发重渲染的值。

一句话定义

如果一个值需要记住,但它的变化不应该驱动界面更新,就优先考虑 useRef

最常见的两个用途

引用 DOM 节点

例如聚焦输入框、读取元素尺寸、配合第三方库初始化。

保存可变值

例如定时器 ID、上一次值、某个实例对象。

为什么它和 state 不一样

  • state 变化会触发重渲染
  • ref.current 变化不会触发重渲染

最小例子

const inputRef = useRef<HTMLInputElement | null>(null)
const timerRef = useRef<number | null>(null)

两个典型例子

例子 1:聚焦输入框

function SearchInput() {
  const inputRef = useRef<HTMLInputElement | null>(null)

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

  return <input ref={inputRef} />
}

例子 2:保存最新值给长期回调读取

function Counter() {
  const [count, setCount] = useState(0)
  const countRef = useRef(count)

  useEffect(() => {
    countRef.current = count
  }, [count])

  useEffect(() => {
    const id = window.setInterval(() => {
      console.log(countRef.current)
    }, 1000)

    return () => window.clearInterval(id)
  }, [])

  return <button onClick={() => setCount(c => c + 1)}>{count}</button>
}

这里 ref 的价值是:让长期存在的定时器回调可以读到最新值,而不必每次都重建定时器。

它为什么适合解决闭包旧值问题

因为 ref 对象本身在多次渲染间是稳定的,而你可以手动更新 ref.current

所以:

  • 回调可以长期存在
  • 读取到的却是最新的 current

什么时候不要用它

  • 只要某个值变化后应该更新界面,就不要偷懒用 useRef
  • 不要把本来应该进入 React 数据流的状态藏进 ref
  • 不要把 ref.current 的变化误以为能自动触发渲染

一个最实用的判断题

如果这个值变化后,用户应该看到 UI 跟着变化,用 state。

如果这个值只是需要被记住、被读取、被 cleanup,但不需要刷新界面,用 ref。

最短记忆方式

useRef 是“不参与渲染的记忆格”,不是 state 的替代品。

面试要点

来自 react-use-ref-interview-question 的面试视角整理。

一句话回答

useRef 适合保存跨渲染周期持续存在、但变化后不需要触发界面更新的值;而 state 变化后会驱动组件重新渲染。

最稳的回答主线

  • useRef 常用于 DOM 引用、定时器 ID、上一次值
  • state 适合真正影响 UI 的数据
  • 不要把本该进入 React 数据流的状态偷偷塞进 ref

一个更完整的面试表达

可以这样答:

useRef 的核心价值是“跨渲染记住一个值,但它变化后不会触发组件重新渲染”。所以它特别适合两类场景:一类是拿 DOM 节点,另一类是保存 timer id、上一次值、第三方实例这种不参与渲染的可变值。
和 state 最大的区别是,state 用来驱动 UI,ref 用来保存不驱动 UI 的记忆。

一个最常见的例子

function SearchInput() {
  const inputRef = useRef<HTMLInputElement | null>(null)

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

  return <input ref={inputRef} />
}

这里如果不用 ref,就很难拿到真实 DOM。

一个加分点

如果面试官继续追问,可以补一句:

useRef 还经常用来解决闭包旧值问题,因为 ref 对象本身是稳定的,但 ref.current 可以手动更新成最新值。

一个常见反例

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

这不会让界面自动刷新,所以如果这个值变化后用户应该看到 UI 改变,就不该用 ref,而应该用 state。

最短记忆方式

ref 记值不刷新,state 变了会重渲染。

创建于 2026/3/19 更新于 2026/5/27