用 useRef 操作 DOM 并保存实例值,同时不破坏渲染的纯粹性。
在 Kodokon 中打开本课useRef 返回一个可变的盒子——一个只有 current 属性的对象——它的标识在每次渲染中都保持不变。它与 state 有两个根本区别:修改 ref.current 不会触发任何重新渲染,而且改动立即可见,无需等到下一次渲染。由此衍生出两类用途:引用一个 DOM 节点,以及存储一个必须在多次渲染中存活、却又不驱动显示的实例值。
import { useEffect, useRef } from "react";
function SearchField() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <input ref={inputRef} type="search" />;
}在实例值这一面,任何必须存留却不引发渲染的东西都该放进 ref:setInterval 返回的 id、某个外部库的实例(一张地图、一个编辑器、一个视频播放器),或者上一次渲染留下的值。金科玉律始终不变:渲染必须是 props 和 state 的纯函数。ref 在 effect 和事件处理函数里被读写,而不是在渲染期间。
import { useEffect, useRef } from "react";
function usePrevious(value) {
const ref = useRef(undefined);
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}要从你自己的组件里暴露一个 DOM 节点,把 ref 往下传:自 React 19 起,ref 就是函数组件的一个普通 prop;在那之前,必须经过 forwardRef。最后要养成一个习惯:当 state 足以描述结果时(一个 CSS class、一个 disabled 属性),优先采用声明式的方式。把 ref 留给 React 覆盖不到的领域:聚焦、文本选择、测量元素、滚动、媒体播放。
import { useRef } from "react";
function TextField({ ref, ...props }) {
return <input ref={ref} {...props} />;
}
function Form() {
const fieldRef = useRef(null);
return (
<>
<TextField ref={fieldRef} />
<button onClick={() => fieldRef.current.focus()}>
Give focus
</button>
</>
);
}