在 React 开发中,useRef 和 forwardRef 是两个重要的工具,特别是在我们需要直接操作 DOM 或者需要将父组件中的 ref 转发给子组件内部的 DOM 元素时。这篇文章将详细介绍如何使用 useRef 和 forwardRef 来解决常见的 Ref 丢失问题,并通过实际代码示例帮助我们更好地理解和应用这些概念。
一、什么是 useRef?
✅ 定义
useRef 是一个 React Hook,它允许你创建一个引用对象(ref),这个对象在整个组件生命周期中保持不变。你可以用它来保存对 DOM 元素或组件实例的引用,或者存储任何可变值。
📦 语法
const ref = useRef(initialValue);
initialValue:初始值,通常为null(用于绑定 DOM)或其他基础类型。
🧪 示例:自动聚焦输入框
import React, { useRef, useEffect } from 'react';
function App() {
const inputRef = useRef(null);
useEffect(() => {
// 组件挂载后聚焦输入框
inputRef.current.focus();
}, []);
return (
<div>
<input type="text" ref={inputRef} />
</div>
);
}
在这个例子中:
inputRef是一个引用对象,指向<input>元素。inputRef.current访问到的就是<input>元素本身,可以调用其方法如.focus()。
二、为什么需要 forwardRef?
❗问题来了
如果把 input 封装成一个自定义组件:
function Guang() {
return <input type="text" />;
}
然后在父组件中尝试控制它:
function App() {
const inputRef = useRef(null);
return <Guang ref={inputRef} />;
}
就会发现:inputRef.current 是 null,拿不到 input 元素!
❗为什么会这样?
因为 React 的组件默认不会自动转发 ref。也就是说:
父组件传来的
ref,并不会自动绑定到子组件里的 DOM 元素上。
三、什么是 forwardRef?
✅ forwardRef 的作用
forwardRef 是 React 提供的一个工具,用来把父组件传来的 ref 转发给子组件内部的 DOM 元素。
✅ 举个例子
假设我们有一个自定义组件 Guang,并希望在父组件中通过 ref 控制它的内部 DOM 元素:
function Guang(props, ref) {
return (
<div>
<input type="text" ref={ref} />
</div>
);
}
const WrapperGuang = forwardRef(Guang);//把 `Guang` 包装成一个可以接收 `ref` 的组件
Guang接收props和ref- 把
ref传给了input,这样父组件就能通过ref访问到这个 input
现在我们就可以在父组件中控制这个 input:
function App() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current?.focus(); // ✅ 可以聚焦了!
}, []);
return (
<div className='App'>
<WrapperGuang ref={inputRef} />
</div>
);
}
- 组件挂载后,input 自动聚焦
forwardRef就像是一个“信号中继站”,把遥控器的信号(ref)传给屋子里的电视(DOM 元素)。
四、常见使用场景
✅ 场景一:自动聚焦输入框
useEffect(() => {
inputRef.current.focus();
}, [])
✅ 场景二:滚动到某个元素
inputRef.current.scrollIntoView({ behavior: 'smooth' });
✅ 场景三:控制视频播放
const videoRef = useRef(null);
videoRef.current.play();
✅ 场景四:封装可聚焦的组件
const MyInput = forwardRef((props, ref) => (
<input ref={ref} {...props} />
));