React `useRef` Hook: 全面解析

React useRef Hook: 全面解析

useRef 是 React 中用于创建持久化可变引用的核心 Hook,它解决了函数组件中无法直接访问 DOM 元素和保存可变值的问题。

核心特性

  1. 跨渲染持久化:返回的对象在组件整个生命周期中保持不变
  2. 变更不会触发重渲染 :修改 .current 属性不会导致组件更新
  3. 直接访问 DOM 节点:最常用的场景
  4. 保存任意可变值:类似类组件的实例属性

基础语法

javascript 复制代码
const refContainer = useRef(initialValue);
  • initialValue:初始值(通常为 null
  • refContainer.current:访问/修改引用值

主要使用场景

1. 访问 DOM 元素(最常见用法)

jsx 复制代码
function TextInput() {
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus(); // 直接操作DOM
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>
  );
}

2. 存储可变值(不触发重渲染)

jsx 复制代码
function Timer() {
  const [count, setCount] = useState(0);
  const intervalRef = useRef(); // 存储定时器ID

  useEffect(() => {
    intervalRef.current = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
    
    return () => clearInterval(intervalRef.current);
  }, []);

  return <div>计时: {count} 秒</div>;
}

3. 保存上一次状态

jsx 复制代码
function Counter() {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef();
  
  useEffect(() => {
    prevCountRef.current = count; // 在渲染后更新
  });
  
  return (
    <div>
      <p>当前值: {count}</p>
      <p>上一次值: {prevCountRef.current ?? '无'}</p>
      <button onClick={() => setCount(c => c + 1)}>增加</button>
    </div>
  );
}

4. 存储复杂计算结果(跳过重复计算)

jsx 复制代码
function ExpensiveComponent() {
  const [value, setValue] = useState(0);
  const computedValueRef = useRef();
  
  if (!computedValueRef.current) {
    // 只计算一次
    computedValueRef.current = heavyComputation(value);
  }
  
  return <div>{computedValueRef.current}</div>;
}

useState 的关键区别

特性 useRef useState
触发重渲染
存储类型 可变值 (current 属性) 不可变状态
访问方式 直接访问 .current 通过状态变量
更新机制 同步更新 异步批量更新
适合场景 DOM引用/缓存值/避免重渲染计算 UI渲染相关状态

高级用法

1. 自定义 Hook 封装

javascript 复制代码
// 获取上一次值的Hook
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}

2. 结合 forwardRef 暴露组件内部 DOM

jsx 复制代码
const CustomInput = forwardRef((props, ref) => {
  return <input ref={ref} {...props} />;
});

function Parent() {
  const inputRef = useRef();
  // 可直接操作 CustomInput 内部的 input
  return <CustomInput ref={inputRef} />;
}

3. 测量 DOM 元素

jsx 复制代码
function MeasureExample() {
  const divRef = useRef(null);
  const [size, setSize] = useState({});
  
  useLayoutEffect(() => {
    if (divRef.current) {
      setSize({
        width: divRef.current.offsetWidth,
        height: divRef.current.offsetHeight
      });
    }
  }, []);

  return (
    <div ref={divRef}>
      元素尺寸: {size.width} x {size.height}
    </div>
  );
}

注意事项

  1. 不要在渲染期间修改 refs

    修改 ref.current 应放在事件处理、useEffect 或生命周期方法中

  2. 避免过度使用

    优先考虑 React 数据流(props/state),仅当确实需要时才使用 refs

  3. 初始渲染时 current 为 null

    访问 DOM 元素时需做空值检查:

    js 复制代码
    useEffect(() => {
      if (inputRef.current) {
        inputRef.current.focus();
      }
    }, []);
  4. 服务端渲染(SSR)问题

    SSR 期间 refs 不会附加到 DOM,应在 useEffect 中使用


性能优化

jsx 复制代码
function HeavyComponent() {
  const elementRef = useRef();
  
  // 避免在渲染期间进行昂贵操作
  useEffect(() => {
    if (elementRef.current) {
      performExpensiveDOMOperation(elementRef.current);
    }
  }, []);

  return <div ref={elementRef}>...</div>;
}

总结

useRef 是 React 函数组件的"逃生舱",主要解决两类问题:

  1. 访问 DOM 元素(表单聚焦、媒体控制、动画等)
  2. 存储可变值(计时器ID、缓存数据、前值记录等)

正确使用原则:

  • 需要直接操作 DOM 时使用
  • 需要存储与渲染无关的值时使用
  • 避免在渲染期间修改 .current
  • 结合 forwardRef 暴露组件内部 DOM
  • 优先使用 React 数据流,ref 作为最后手段
相关推荐
清山博客1 小时前
OpenCV 人脸识别和比对工具
前端·webpack·node.js
要加油哦~1 小时前
AI | 实践教程 - ScreenCoder | 多agents前端代码生成
前端·javascript·人工智能
程序员Sunday1 小时前
说点不一样的。GPT-5.3 与 Claude Opus 4.6 同时炸场,前端变天了?
前端·gpt·状态模式
yq1982043011561 小时前
静思书屋:基于Java Web技术栈构建高性能图书信息平台实践
java·开发语言·前端
aPurpleBerry1 小时前
monorepo (Monolithic Repository) pnpm rush
前端
青茶3601 小时前
php怎么实现订单接口状态轮询请求
前端·javascript·php
鹏北海2 小时前
micro-app 微前端项目部署指南
前端·nginx·微服务
发现一只大呆瓜2 小时前
虚拟列表:从定高到动态高度的 Vue 3 & React 满分实现
前端·vue.js·react.js
css趣多多2 小时前
add组件增删改的表单处理
java·服务器·前端
证榜样呀2 小时前
2026 大专计算机专业必考证书推荐什么
大数据·前端