useRef
是 React 中一个非常有用的 Hook,它允许你在函数组件中访问和保持对 DOM 元素、React 组件实例或任意可变值的引用。以下是一些常见的使用 useRef
的场景:
1. 访问 DOM 元素
当你需要直接操作 DOM 元素时,可以使用 useRef
来获取对它的引用。
const inputRef = useRef<HTMLInputElement>(null);
// 在 JSX 中绑定 ref
<input type="text" ref={inputRef} />
2. 保存组件状态(不触发重新渲染)
如果你有一些数据需要在组件生命周期内保持不变,并且这些数据的变化不需要触发组件重新渲染,那么你可以使用 useRef
。适合存储与 UI 无关的临时数据(如计时器 ID、DOM 引用等)
- 存储 DOM 元素引用:直接访问或操作 DOM(如聚焦输入框、测量元素尺寸)。
- 缓存上一次的 props/state:通过
useRef
结合useEffect
比较当前值与前一个值的变化 。 - 避免闭包中的值过期:在
useEffect
或回调函数中存储依赖项的最新值(如定时器参数)。 - 性能优化:存储不需要触发更新的计算结果或中间状态(如渲染计数器)
const timerId = useRef<number | null>(null);
useEffect(() => {
timerId.current = window.setInterval(() => {
// do something },
1000);
return () => { if (timerId.current) {
window.clearInterval(timerId.current);
}
};
}, []);
3. 在回调中访问最新的状态
有时候你希望在一个异步操作中访问到状态的最新值,而不是捕获当时的值。这时候可以用 useRef
来存储这个状态。
const [count, setCount] = useState(0);
const countRef = useRef(count);
useEffect(() => { countRef.current = count; }, [count]); // 在某个异步操作中
setTimeout(() => { console.log(`Current count is ${countRef.current}`); }, 1000);
4. 跨 Hook 或 Effect 共享数据
如果你有多个 Hook 或 Effect 需要共享一些数据,并且你不希望因为这些数据的变化而触发额外的渲染,那么可以考虑用 useRef
存储它们。
const dataRef = useRef({ userId: 123, fetchTime: new Date() });
useEffect(() => { dataRef.current.userId = 456; }, []);
5. 控制子组件的行为
当父组件需要调用子组件的方法或者传递信息给子组件时,可以通过 useRef
来实现。
const childRef = useRef<{ focusInput: () => void }>(null);
<button onClick={() => childRef.current?.focusInput()}>
Focus Input in Child Component
</button>
<ChildComponent ref={childRef} />
6. 实现自定义 Hook 中的状态管理
在创建自定义 Hook 时,useRef
可以用来存储内部状态,这有助于避免不必要的重新渲染。
function usePrevious(value) {
const ref = useRef();
useEffect(() => { ref.current = value; });
return ref.current;
}
7. 管理第三方库实例
当你集成第三方库时,可能需要持有该库实例的引用,这时 useRef
就派上用场了。
const mapRef = useRef<Map>(null); useEffect(() => { mapRef.current = new Map(); // 假设这是一个地图库的实例 // 初始化地图... return () => { mapRef.current.remove(); // 清理资源 }; }, []);
总结
- 访问 DOM:通过 ref 获取 DOM 元素。
- 保存状态:保存不会导致重新渲染的数据。
- 跨作用域通信:在不同副作用之间共享数据。
- 控制子组件:暴露子组件的方法供父组件调用。
- 优化性能:避免因数据变化引起的不必要的重新渲染。