前端面试题 - 59. useRef / ref / forwardsRef 的区别是什么?

645 阅读2分钟

区别

useRefrefforwardRef都可以用于在React组件中保存和访问状态或DOM节点,但它们的用法和适用场景有所不同。

  • useRef适用于函数组件中的状态管理
  • ref适用于类组件和函数组件中的DOM节点操作
  • forwardRef适用于从父组件向子组件传递ref属性。

useRef是React提供的一个Hook函数,它返回一个可变的Ref对象,可以用于在函数组件中保存和访问组件的状态或DOM节点useRef返回的Ref对象在组件的整个生命周期内都保持不变,可以用于避免由于重新渲染导致的状态丢失或副作用重复执行等问题。

ref是React中的一个属性,可以用于在类组件中保存和访问组件的状态或DOM节点ref属性可以直接用于DOM元素、类组件实例或函数组件的组件实例,但需要注意的是,当用于函数组件时,ref只能是null或一个回调函数。

forwardRef是React中的一个高阶组件函数,可以用于将ref属性从父组件传递到子组件。它接收一个渲染函数作为参数,并返回一个新的组件,新组件将父组件传递的ref属性转发给子组件。forwardRef通常用于封装具有DOM操作或动画效果的子组件,以便从父组件中控制子组件的行为。

代码示例

一个简单的代码示例,演示了useRefrefforwardRef的区别:

import React, { useRef, forwardRef } from "react";
// 用useRef保存函数组件的状态
function Counter() {
  const countRef = useRef(0);
  const increment = () => {
    countRef.current++;
    console.log(countRef.current);
  };
  return <button onClick={increment}>Clicked {countRef.current} times</button>;
}
// 用ref操作类组件的DOM节点
class MyInput extends React.Component {
  focus() {
    this.inputRef.focus();
  }
  render() {
    return <input type="text" ref={el => (this.inputRef = el)} />;
  }
}
// 用forwardRef将ref传递给子组件
const FancyButton = forwardRef((props, ref) => (
  <button ref={ref} className="fancy-button">
    {props.children}
  </button>
));
function App() {
  // 使用ref操作子组件的DOM节点
  const buttonRef = useRef(null);
  const handleClick = () => {
    buttonRef.current.style.color = "red";
  };
  return (
    <div>
      <Counter />
      <MyInput ref={el => (this.myInputRef = el)} />
      <button onClick={handleClick}>Click me to change color</button>
      {/* 通过forwardRef将ref传递给子组件 */}
      <FancyButton ref={buttonRef}>Hello world</FancyButton>
    </div>
  );
}

在这个示例中,我们首先用useRef保存函数组件的状态,实现了一个简单的计数器。然后用ref属性操作了类组件MyInput的DOM节点,实现了将焦点移动到输入框的功能。最后用forwardRefref传递给子组件FancyButton,实现了修改按钮颜色的效果。 通过这个示例,我们可以看到useRefrefforwardRef的不同用法和适用场景。useRef适用于函数组件中的状态管理,ref适用于类组件和函数组件中的DOM节点操作,forwardRef适用于从父组件向子组件传递ref属性。