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 或实例的场景。
相关推荐
Kellen5 小时前
ReactDOM.preload
前端·react.js
烟西6 小时前
手撕React18源码系列 - Event-Loop模型
前端·javascript·react.js
用户47949283569158 小时前
面试官问 React Fiber,这一篇文章就够了
前端·javascript·react.js
CoderHing9 小时前
告别 try/catch 地狱:用三元组重新定义 JavaScript 错误处理
前端·javascript·react.js
大风起兮云飞扬丶11 小时前
react大列表更新时优化
前端·react.js·前端框架
黛色正浓11 小时前
【React18+TypeScript】React 18 for Beginners
javascript·react.js·typescript
Zhi.C.Yue11 小时前
React 状态更新中的双缓冲机制、优先级调度
前端·javascript·react.js
前端郭德纲12 小时前
React 19.2 已发布,现已上线 npm!
前端·react.js·npm
随风一样自由13 小时前
React编码时,什么时候用js文件,什么时候用jsx文件?
开发语言·javascript·react.js
AI分享猿13 小时前
雷池 WAF vs React 高危漏洞:1 毫秒检测延迟,护住全栈业务安全
前端·安全·react.js