React 中的 `useRef`、`ref` 和 `forwardRef`:区别与使用场景

基本概念

在 React 开发中,useRefrefforwardRef 是三个与引用(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 使用 forwardRefref 转发到 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 或实例的场景。
相关推荐
mapbar_front1 小时前
react项目开发—关于代码架构/规范探讨
前端·react.js
需要兼职养活自己1 小时前
react高阶组件
前端·react.js
今天周二2 小时前
vite 将react老项目中的没有兼容处理的写法转成兼容性写法
react.js
GISBox2 小时前
GISBox如何让GeoTIFF突破Imagery Provider加载限制?
react.js·json·gis
天蓝色的鱼鱼4 小时前
Next.js 渲染模式全解析:如何正确选择客户端与服务端渲染
前端·react.js·next.js
果粒chenl7 小时前
React学习(四) --- Redux
javascript·学习·react.js
LRH9 小时前
React 双缓存架构与 diff 算法优化
前端·react.js
中微子9 小时前
别再被闭包坑了!React 19.2 官方新方案 useEffectEvent,不懂你就 OUT!
前端·javascript·react.js
1in9 小时前
一文解析UseState的的执行流程
前端·javascript·react.js
鹏多多10 小时前
React无限滚动插件react-infinite-scroll-component的配置+优化+避坑指南
前端·javascript·react.js