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.current 为 null,调用 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,让它成为你开发中的得力助手。