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 或实例的场景。
相关推荐
mit6.8242 小时前
[AI React Web] 包与依赖管理 | `axios`库 | `framer-motion`库
前端·人工智能·react.js
晓得迷路了3 小时前
栗子前端技术周刊第 94 期 - React Native 0.81、jQuery 4.0.0 RC1、Bun v1.2.20...
前端·javascript·react.js
江城开朗的豌豆3 小时前
React状态更新踩坑记:我是这样优雅修改参数的
前端·javascript·react.js
小遁哥21 小时前
也是用上webworker了
react.js·性能优化
小妖6661 天前
react-router 怎么设置 basepath 设置网站基础路径
前端·react.js·前端框架
Ratten1 天前
Taro React 之行为验证码之文字点选
react.js
GISer_Jing1 天前
React手撕组件和Hooks总结
前端·react.js·前端框架
布兰妮甜2 天前
CSS Houdini 与 React 19 调度器:打造极致流畅的网页体验
前端·css·react.js·houdini
快起来别睡了2 天前
React Hook 核心指南:从实战到源码,彻底掌握状态与副作用
react.js
FSHOW3 天前
记一次开源_大量SVG的高性能渲染
前端·react.js