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