跳转到主要内容

使用 Ref 引用值

有些值需要在渲染之间被“记住”,但它们变化时不应该触发 UI 更新(例如定时器 id、缓存、DOM 节点)。 这时你需要的是 Ref

获取 DOM 节点:聚焦输入框

TypeScript
import { useRef } from 'react';

export default function SearchBox() {
  const inputRef = useRef<HTMLInputElement | null>(null);

  function focusInput() {
    inputRef.current?.focus();
  }

  return (
    <>
      <input ref={inputRef} placeholder="搜索..." />
      <button onClick={focusInput}>聚焦输入框</button>
    </>
  );
}

保存可变值:定时器 id

这个例子里,秒数需要渲染(用 State),但 interval id 不需要渲染(用 Ref)。

TypeScript
import { useRef, useState } from 'react';

export default function Stopwatch() {
  const [seconds, setSeconds] = useState(0);
  const intervalIdRef = useRef<number | null>(null);

  function start() {
    if (intervalIdRef.current !== null) return;
    intervalIdRef.current = window.setInterval(() => {
      setSeconds((s) => s + 1);
    }, 1000);
  }

  function stop() {
    if (intervalIdRef.current === null) return;
    window.clearInterval(intervalIdRef.current);
    intervalIdRef.current = null;
  }

  return (
    <>
      <p>{seconds}s</p>
      <button onClick={start}>开始</button>
      <button onClick={stop}>停止</button>
    </>
  );
}

保存“上一次的值”

TypeScript
import { useEffect, useRef, useState } from 'react';

export default function PreviousValueDemo() {
  const [value, setValue] = useState('');
  const prevRef = useRef('');

  useEffect(() => {
    prevRef.current = value;
  }, [value]);

  return (
    <>
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <p>当前:{value}</p>
      <p>上一次:{prevRef.current}</p>
    </>
  );
}
常见误区
  • 把需要渲染的数据放到 Ref:你会发现 UI 不更新。
  • 在渲染阶段读写 ref.current 来做副作用:尽量把副作用放到事件处理或 Effect 中(见 使用 Effect 同步)。

下一步

动手练习

运行并修改下面的组件,熟悉交互式示例的编辑与预览。

🌐浏览器运行
使用 Ref 引用值 - React 文档 - React 文档