基本概念
在 React 开发中,useRef、ref 和 forwardRef 是三个与引用(reference)相关的核心概念。它们虽然都与 DOM 操作或组件实例的引用有关,但各自的使用场景和功能有所不同。本文将详细探讨它们的区别,并通过示例帮助你更好地理解它们的应用。
1. ref:React 中的引用
ref 是 React 提供的一种机制,用于直接访问 DOM 元素或组件实例。通常情况下,React 推荐使用声明式的数据流来管理组件状态,但在某些场景下,直接操作 DOM 是不可避免的。这时,ref 就派上了用场。
使用场景
访问 DOM 元素(如输入框、按钮等)。
获取子组件的实例(仅限于类组件)。
示例
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 元素。
存储可变值(类似于类组件中的实例变量)。
示例
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 还可以用来存储可变值,这些值在组件的生命周期中保持不变,且不会触发重新渲染。
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 元素或实例。
示例
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 元素。
总结
ref:主要用于类组件中,用于访问 DOM 元素或子组件实例。
useRef:用于函数组件中,既可以访问 DOM 元素,也可以存储可变值。
forwardRef:用于将 ref 从父组件转发到子组件,适用于需要跨组件访问 DOM 或实例的场景。