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

基本概念

在 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 或实例的场景。
相关推荐
weixin_448119949 小时前
Datawhale Easy Data × AI:构建知识与记忆驱动的 Agent笔记8
人工智能·笔记·react.js
EatFan12 小时前
React 项目踩坑实录:useEffect 闭包陷阱、Context 性能陷阱与 React 18 升级避坑排查手册
前端·javascript·react.js·react·react hooks·useeffect·闭包陷阱
梦想的颜色16 小时前
【编程实战】AI 时代 APP 开发全栈硬核指南:技术选型 + AI 架构 + 模型落地全维度决策
python·flutter·react native·react.js·ai·桌面应用·milvus
知野小兔16 小时前
对比react钩子函数
react.js
阿狗童鞋2 天前
React实战指南
前端·react.js·前端框架
用户298698530142 天前
React 中实现 Word 与 Markdown 双向转换的实践记录
javascript·react.js·markdown
JavaPub-rodert2 天前
开源一套 Go + React 后台管理系统,支持 RBAC 权限管理、Docker 一键部署!
react.js·golang·开源
kill5223 天前
useRef
前端·javascript·react.js
西柚小萌新3 天前
【LLM&&AI应用开发 八股文】--4.2.Agent智能体(中)
前端·javascript·react.js