基本概念
在 React 开发中,useRef
、ref
和 forwardRef
是三个与引用(reference)相关的核心概念。它们虽然都与 DOM 操作或组件实例的引用有关,但各自的使用场景和功能有所不同。本文将详细探讨它们的区别,并通过示例帮助你更好地理解它们的应用。
1. ref
:React 中的引用
ref
是 React 提供的一种机制,用于直接访问 DOM 元素或组件实例。通常情况下,React 推荐使用声明式的数据流来管理组件状态,但在某些场景下,直接操作 DOM 是不可避免的。这时,ref
就派上了用场。
使用场景
- 访问 DOM 元素(如输入框、按钮等)。
- 获取子组件的实例(仅限于类组件)。
示例
jsx
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
// 访问 DOM 元素
this.myRef.current.focus();
}
render() {
return <input type="text" ref={this.myRef} />;
}
}
在上面的例子中,React.createRef()
创建了一个 ref
,并将其附加到 input
元素上。通过 this.myRef.current
,我们可以直接访问该 DOM 元素。
2. useRef
:函数组件中的引用
useRef
是 React Hooks 提供的一个 API,用于在函数组件中创建引用。与 React.createRef()
类似,useRef
也可以用来访问 DOM 元素或存储可变值。不同的是,useRef
在函数组件的每次渲染中都会返回同一个引用对象。
使用场景
- 访问 DOM 元素。
- 存储可变值(类似于类组件中的实例变量)。
示例
jsx
function MyComponent() {
const inputRef = React.useRef(null);
React.useEffect(() => {
// 访问 DOM 元素
inputRef.current.focus();
}, []);
return <input type="text" ref={inputRef} />;
}
在这个例子中,useRef
创建了一个引用,并将其附加到 input
元素上。与类组件中的 ref
类似,inputRef.current
可以访问 DOM 元素。
存储可变值
useRef
还可以用来存储可变值,这些值在组件的生命周期中保持不变,且不会触发重新渲染。
jsx
function Timer() {
const timerRef = React.useRef(0);
const startTimer = () => {
timerRef.current = setInterval(() => {
console.log("Timer is running...");
}, 1000);
};
const stopTimer = () => {
clearInterval(timerRef.current);
};
return (
<div>
<button onClick={startTimer}>Start Timer</button>
<button onClick={stopTimer}>Stop Timer</button>
</div>
);
}
在这个例子中,timerRef
用于存储定时器的 ID,即使组件重新渲染,timerRef.current
的值也不会丢失。
3. forwardRef
:转发引用
forwardRef
是 React 提供的一个高阶函数,用于将 ref
从父组件转发到子组件。这在某些场景下非常有用,例如当你需要在父组件中直接访问子组件的 DOM 元素或实例时。
使用场景
- 将
ref
传递给子组件。 - 在父组件中访问子组件的 DOM 元素或实例。
示例
jsx
const ChildComponent = React.forwardRef((props, ref) => {
return <input type="text" ref={ref} />;
});
function ParentComponent() {
const inputRef = React.useRef(null);
React.useEffect(() => {
// 访问子组件的 DOM 元素
inputRef.current.focus();
}, []);
return <ChildComponent ref={inputRef} />;
}
在这个例子中,ChildComponent
使用 forwardRef
将 ref
转发到 input
元素上。父组件 ParentComponent
可以通过 inputRef
直接访问子组件的 input
元素。
4. 三者的区别
特性 | ref |
useRef |
forwardRef |
---|---|---|---|
使用场景 | 类组件中访问 DOM 或组件实例 | 函数组件中访问 DOM 或存储可变值 | 将 ref 从父组件转发到子组件 |
创建方式 | React.createRef() |
React.useRef() |
React.forwardRef() |
适用组件 | 类组件 | 函数组件 | 函数组件或类组件 |
存储值 | 仅用于 DOM 或组件实例 | 可用于 DOM 或存储任意可变值 | 用于转发 ref |
5. 总结
ref
:主要用于类组件中,用于访问 DOM 元素或子组件实例。useRef
:用于函数组件中,既可以访问 DOM 元素,也可以存储可变值。forwardRef
:用于将ref
从父组件转发到子组件,适用于需要跨组件访问 DOM 或实例的场景。