useRef--笔记

33 阅读2分钟

在 React 中,useRef 是一个内置 Hook,用于创建一个可变的 ref 对象,其 .current 属性可以保存任何值,并且在组件的整个生命周期内保持不变。以下是它的核心用法和适用场景:

一、基本用法

1. 获取 DOM 元素引用

import { useRef } from 'react'; 
function TextInputWithFocusButton() { 
    const inputRef = useRef(null); 
    const handleClick = () => {
        inputRef.current.focus(); 
        // 获取 DOM 节点并调用 focus 方法 
    };
    return ( 
        <> 
            <input ref={inputRef} type="text" /> 
            <button onClick={handleClick}>聚焦输入框</button>
        </>
    );
}
  • useRef(null) 创建一个 ref 对象,初始值为 null
  • 通过 ref={inputRef} 将 ref 绑定到 DOM 元素,inputRef.current 会指向该 DOM 节点。

2. 保存可变值(替代 instance variables

import { useRef, useEffect } from 'react'; 
function Timer() { 
    const intervalRef = useRef(null); // 保存定时器 ID 
    const countRef = useRef(0); // 保存计数状态,不会触发重新渲染 
    useEffect(() => { 
        intervalRef.current = setInterval(() => { 
            countRef.current += 1; 
            console.log('计数:', countRef.current);
        }, 1000); 
        return () => { 
            clearInterval(intervalRef.current); // 清理定时器 
        }; 
    }, []); 
    return <div>后台计时器运行中...</div>; 
} 
  • ref 对象的值变化不会触发组件重新渲染,适合存储不需要影响 UI 的数据(如定时器 ID、DOM 节点)。

二、适用场景

1. 操作 DOM

  • 聚焦输入框、滚动到特定位置、测量 DOM 尺寸等:
const divRef = useRef(null);
useEffect(() => { 
    const height = divRef.current.offsetHeight; 
    console.log('div 高度:', height); 
}, []); 
return <div ref={divRef}>测量我</div>; 

2. 存储不需要触发渲染的变量

  • 避免闭包陷阱:在定时器、异步回调中获取最新值:
const latestCount = useRef(count); 
// 保存最新的 count 值 
useEffect(() => { 
    latestCount.current = count; // 每次 count 变化时更新 
}, [count]);
useEffect(() => { 
    const interval = setInterval(() => { 
        console.log('最新 count:', latestCount.current); // 总是获取最新值 
    }, 1000); 
    return () => clearInterval(interval); 
}, []); 

3. 跨渲染周期保存值

  • 在组件多次渲染之间保持数据:
function App() { 
    const prevValue = useRef(null); // 保存上一次的 props 或 state 
    useEffect(() => { 
        prevValue.current = props.value; // 组件渲染后更新 
    }); 
    return <div>之前的值: {prevValue.current}</div>;
} 

4. 优化性能(缓存复杂对象)

  • 使用 useRef 缓存昂贵的计算结果,避免重复计算:
const cachedValue = useRef(null); 
if (!cachedValue.current) { 
    cachedValue.current = expensiveCalculation(); // 只计算一次 
}

三、注意事项

  1. 不要在渲染过程中修改 ref.current 渲染期间修改 ref 可能导致意外行为,应在事件处理函数或副作用中修改。
  2. ref 更新不会触发渲染state 不同,修改 ref.current 不会导致组件重新渲染。
  3. 避免过度使用 优先使用 state 管理影响 UI 的数据,仅在必要时使用 ref(如操作 DOM、存储临时值)。

四、对比其他 Hook

Hook用途是否触发渲染
useState管理状态,状态变化触发重新渲染
useRef存储可变值、获取 DOM 引用,不触发渲染
useCallback缓存函数引用,避免不必要的依赖变化
useMemo缓存计算结果,优化性能

总结

  • 何时用:操作 DOM、存储不需要触发渲染的变量、跨渲染周期保存数据。
  • 为何用:避免闭包陷阱、优化性能、获取 DOM 节点。
  • 注意点:不要在渲染期间修改 refref 更新不会触发重渲染。 如果需要在组件间共享 ref,可以结合 useImperativeHandleforwardRef 使用。