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 或实例的场景。
相关推荐
安心不心安11 小时前
React hooks——useReducer
前端·javascript·react.js
啃火龙果的兔子12 小时前
react19+nextjs+antd切换主题颜色
前端·javascript·react.js
谢尔登14 小时前
【React Native】布局和 Stack 、Slot
javascript·react native·react.js
几颗流星15 小时前
01 react入门
前端·react.js
遂心_17 小时前
React Fragment与DocumentFragment:提升性能的双剑合璧
前端·javascript·react.js
混水的鱼17 小时前
PasswordValidation 密码校验组件实现与详解
前端·react.js
自己记录_理解更深刻17 小时前
默认导出 vs 具名导出
react.js
WildBlue17 小时前
小白也能懂!react-router-dom 超详细指南🚀
前端·react.js
孟陬18 小时前
tailwind“移动端优先”在隐藏元素方面的问题 - tailwindcss 系列
react.js
颜酱18 小时前
使用useReducer和Context进行React中的页面内部数据共享
前端·javascript·react.js