React Refs(手把手讲解)

React Refs 是什么?初学者必须搞懂的核心概念

你有没有遇到过这样的场景:在 React 中,想直接操作一个 DOM 元素,比如让输入框自动聚焦,或者获取某个 div 的宽高?但你发现,通过状态管理(state)来控制这些行为时,总感觉“不够直接”或者“延迟明显”。这时候,React Refs 就是你的救星。

简单来说,React Refs 就像一个“魔法指针”,它能让你在组件中直接访问到某个 DOM 节点或 React 元素,而不需要经过状态更新的“绕路”。它不参与渲染,也不触发重新渲染,是 React 提供的一种“非响应式”的引用机制。

想象一下,你有一个记事本,平时你用“写”来更新内容(对应 state),但有时候你只想“直接翻到第 5 页”去修改某段文字,这时候你就可以用一个“书签”来快速定位。React Refs 就是这个“书签”。

为什么需要 React Refs?它和 state 有什么区别?

在 React 中,我们习惯用 state 来管理数据变化。但 state 的更新会触发组件重新渲染,这虽然符合“数据驱动视图”的原则,但并非所有场景都需要重新渲染。

比如你有一个输入框,想在组件挂载后自动聚焦。如果你用 state 控制 focus 属性,那每次 focus 变化,组件都会重新渲染,这虽然可行,但显得多余。而用 Refs,你只需要在挂载后直接调用 inputRef.current.focus(),无需触发任何渲染。

对比维度 State React Refs
是否触发重新渲染
是否响应数据变化
适合场景 用于 UI 状态管理 用于直接操作 DOM 或保存可变值
生命周期行为 每次更新都会同步 仅在赋值时更新

举个例子:你写了一个表单组件,用户点击“清空”按钮后,想把输入框的内容清空并聚焦。用 state 控制 value 字段,虽然可以实现,但会触发重新渲染。而用 Refs,你只需:

import React, { useRef } from 'React';

function FormInput() {
  // 创建一个 ref,用来指向 input 元素
  const inputRef = useRef(null);

  const handleClear = () => {
    // 直接操作 DOM,清空值并聚焦
    inputRef.current.value = ''; // 清空输入框内容
    inputRef.current.focus();    // 让输入框获得焦点
  };

  return (
    <div>
      <input ref={inputRef} type="text" placeholder="请输入内容" />
      <button onClick={handleClear}>清空并聚焦</button>
    </div>
  );
}

这里 useRef(null) 创建了一个 ref 对象,它的 current 属性初始为 null,后续会被 React 自动赋值为对应的 DOM 元素。inputRef.current 就是真实的 input 节点,你可以直接调用它的 focus()blur() 方法。

如何创建和使用 React Refs?

React 提供了 useRef Hook 来创建 ref。它是 React 16.8 引入的,用于函数组件中使用 refs。

import React, { useRef } from 'React';

function Counter() {
  // 创建一个 ref,用于保存计数器的值
  const countRef = useRef(0); // 初始值为 0

  const handleClick = () => {
    // 直接修改 ref 的值,不会触发重新渲染
    countRef.current += 1;
    console.log('当前计数:', countRef.current);
  };

  return (
    <div>
      <p>当前计数: {countRef.current}</p>
      <button onClick={handleClick}>点击增加</button>
    </div>
  );
}

关键点说明:

  • useRef(0) 创建一个对象,结构为 { current: 0 }
  • countRef.current 可以随时读写,就像一个普通变量。
  • 但修改 current 不会触发组件重新渲染,非常适合保存“不参与渲染的可变状态”。

这个例子展示了 Ref 的另一个重要用途:保存不参与 UI 更新的可变数据。比如你有一个定时器 ID,或者一个 API 请求的取消函数,用 Ref 保存它们是最佳实践。

使用 Refs 操作 DOM 的真实案例

让我们看一个更完整的例子:一个视频播放器组件,需要在用户点击“播放”按钮时,直接调用 HTML5 的 play() 方法。

import React, { useRef } from 'React';

function VideoPlayer() {
  // 创建一个 ref,用来引用 video 元素
  const videoRef = useRef(null);

  const handlePlay = () => {
    // 直接调用 video 元素的 play 方法
    videoRef.current.play();
  };

  const handlePause = () => {
    // 直接调用 pause 方法
    videoRef.current.pause();
  };

  return (
    <div>
      <video ref={videoRef} width="400" height="300">
        <source src="/video.mp4" type="video/mp4" />
        您的浏览器不支持视频播放。
      </video>
      <br />
      <button onClick={handlePlay}>播放</button>
      <button onClick={handlePause}>暂停</button>
    </div>
  );
}

这个例子中,ref={videoRef}videoRef.current 与真实的 <video> 元素绑定。当你调用 videoRef.current.play(),React 不会重新渲染,而是直接执行浏览器原生的播放逻辑。

💡 小贴士:如果 videoRef.currentnull,调用 play() 会报错。因此在实际项目中,建议加个判断:

if (videoRef.current) {
  videoRef.current.play();
}

Refs 与类组件中的 ref 的区别

在类组件中,你可以用 React.createRef() 创建 ref,然后通过 this.refName.current 访问。

class VideoPlayer extends React.Component {
  constructor(props) {
    super(props);
    this.videoRef = React.createRef(); // 创建 ref
  }

  handlePlay = () => {
    this.videoRef.current.play(); // 使用方式不同
  };

  render() {
    return (
      <video ref={this.videoRef} src="/video.mp4" />
    );
  }
}

虽然功能相同,但 useRef 更适合函数式编程风格,且在 Hook 中使用更灵活。推荐在新项目中统一使用 useRef

高级用法:Refs 与回调函数

除了传入 ref 属性,你还可以使用“回调函数”形式的 ref,它在每次更新时被调用,传入当前的 DOM 元素或 null。

function FocusInput() {
  const inputRef = useRef(null);

  // 回调函数形式的 ref
  const handleRef = (element) => {
    if (element) {
      // 当 DOM 元素挂载时,自动聚焦
      element.focus();
    }
  };

  return (
    <input
      ref={handleRef} // 使用回调函数 ref
      type="text"
      placeholder="自动聚焦"
    />
  );
}

这种写法适合需要在挂载时执行某些逻辑的场景,比如初始化第三方库(如 Chart.js、D3.js)时,需要获取容器 DOM。

何时使用 React Refs?最佳实践

React Refs 不是万能的,滥用反而会破坏 React 的“数据驱动”原则。以下是推荐的使用场景:

  • ✅ 需要直接操作 DOM(如聚焦、滚动、测量尺寸)
  • ✅ 保存可变的非渲染数据(如定时器 ID、事件监听器)
  • ✅ 集成第三方库(如地图、富文本编辑器)
  • ✅ 避免不必要的重新渲染

避免在以下场景使用 Refs:

  • ❌ 用于控制 UI 状态(比如显示/隐藏、颜色变化)
  • ❌ 替代 state 进行数据更新
  • ❌ 试图用 ref 实现组件通信(应使用 props 或 context)

总结:React Refs 是你掌控 DOM 的“钥匙”

React Refs 虽然不常被提起,但在实际开发中,它的作用不可替代。它让你在保持 React 响应式特性的同时,拥有了直接操作 DOM 的能力,是 React 生态中“控制力”与“灵活性”的结合。

通过本文,你应该已经掌握了:

  • React Refs 的核心概念与使用场景
  • useRef 的基本语法与常见用法
  • 如何在函数组件中操作 DOM
  • 与类组件 ref 的区别
  • 高级用法与最佳实践

记住:Ref 不是状态,它只是“引用”。用它来控制 DOM,而不是控制视图。当你能精准地使用 React Refs,你的组件将更加高效、流畅,也更接近原生的交互体验。

下次你遇到“想让输入框自动聚焦”或“获取元素尺寸”的问题时,别再绕路了,直接用 React Refs,让它成为你开发中的得力助手。