likes
comments
collection
share

提升React组件灵活性:深入了解forwardRef API的妙用

作者站长头像
站长
· 阅读数 15

阅读时间约为 8 分钟。


昨天我们讨论了 React 中的 useRef 钩子函数: 仅此一文,让你全完掌握React中的useRef钩子函数 ,其中的一个场景是在函数组件中使用 useRef 来创建一个 ref 对象,然后将其绑定到一个元素上,从而获取该元素的引用以便对引用的元素做出各种操作。而当我们想要在父组件中访问子组件的引用时该怎么做呢?

答案是通过 React 的 forwardRef API 来实现。

初识 forwardRef API

forwardRef API 允许我们从父组件向子组件传递一个 ref,从而让父组件能够访问子组件的 DOM 节点或实例。语法如下:

const SomeComponent = forwardRef(render);

通常来说,我们可以通过回调函数的方式来让父组件访问到子组件,也就是通过 props 将回调函数传递给子组件,以便在父组件中访问子组件中的 DOM 节点或实例。但在某些情况下,这种方式不够方便或灵活。而 forwardRef 则可以提供一种更为灵活的方法来解决这个问题。

当我们使用 forwardRef 将子组件包装起来时,我们可以通过 forwardRef 的第二个参数 ref 访问子组件。然后,将该 ref 传递给子组件中需要引用的元素或组件,从而使父组件能够访问子组件的实例或 DOM 节点。这使得 forwardRef 成为一种非常强大和灵活的工具,可以帮助我们轻松地访问和操作子组件中的元素或组件。

如何使用 forwardRef API

要使用 forwardRef 来访问子组件的 DOM 节点或实例,以下两个步骤缺一不可:

  1. 通过 forwardRef 包装子组件

    在父组件中,将 ref 参数传递给通过 forwardRef 函数包装子组件这样父组件:

    const ChildComponent = forwardRef((props, ref) => {
      // 子组件代码
    });
    

    forwardRef 包裹的是一个函数式组件,函数第二个参数就是父组件传递过来的 ref 对象。可以使用我们上一篇文章中探讨的 useRef 方法在父组件中创建一个 ref 对象。

  2. 在子组件中访问 ref 对象

    在子组件中,将 ref 对象绑定到需要访问的元素或组件上,从而使父组件能够访问该 DOM 元素或组件的实例。

    const ChildComponent = forwardRef((props, ref) => {
      return (
        <div>
          {/* ref 对象被绑定在了 input 元素上 */}
          <input type="text" ref={ref} />
        </div>
      );
    });
    

    我们将 ref 对象绑定到 input 元素上,这样在父组件中就可以使用 ref.current 来访问 input 元素的实例。

    const ParentComponent = () => {
      const inputRef = useRef(null);
    
      const handleClick = () => {
        inputRef.current.focus(); // 使子组件 input 元素聚焦
      };
    
      // 渲染子组件,并将 ref 对象传递给它
      return (
        <div>
          <ChildComponent ref={inputRef} />
          <button onClick={handleClick}>Focus input</button>
        </div>
      );
    };
    

    我们使用 useRef 方法来创建一个 ref 对象 inputRef,并将其传递给子组件 ChildComponent。然后,在 handleClick 函数中,我们使用 inputRef.current.focus() 方法来使 input 元素聚焦。

结合 useRef 方法,我们通过上面的两个步骤便能方便的访问到子组件中被绑定了 ref 对象的 DOM 元素了。

除此之外,我们在编写在高阶组件(Higher-Order Component,HOC)时也会经常用到 forwardRef API。高阶组件是一个函数,它接收一个组件作为参数,并返回一个新的组件。forwardRef 可以帮助我们确保 ref 被正确地传递到被包装的组件中。

// 高阶组件 withWrapper 接收一个组件 WrappedComponent 作为参数,并返回一个由 forwardRef 包裹的新组件
function withWrapper(WrappedComponent) {
  return forwardRef((props, ref) => {
    return (
      <div ref={ref}>
        <WrappedComponent {...props} />
      </div>
    );
  });
}

const ChildComponent = ({ text }) => {
  return <div>{text}</div>;
};

const ParentComponent = () => {
  const wrapperRef = useRef(null);

  useEffect(() => {
    console.log(wrapperRef.current); // <div>...</div>
  }, []);

  // 将子组件 ChildComponent 作为参数传递给高阶函数 withWrapper,并返回一个新组建 WrappedChildComponent
  const WrappedChildComponent = withWrapper(ChildComponent);

  // 渲染由高阶组件返回的新组件,并将 ref 对象 wrapperRef 作为一个属性传递给这个新组建 WrappedChildComponent
  return (
    <div>
      <WrappedChildComponent ref={wrapperRef} text="Hello, world!" />
    </div>
  );
};

在上面的示例中,我们定义了一个名为 withWrapper 的高阶组件,该函数接收一个组件作为参数,并返回一个新的组件。这个新的组件将被包裹在一个 div 元素中,并将这个 div 元素的引用作为 ref 传递给被包装的组件。

ParentComponent 父组件中,我们使用 withWrapper 高阶函数来创建一个新的组件 WrappedChildComponent,并将其引用传递给 wrapperRef。这样,当 ParentComponent 渲染时,我们就可以在 useEffect 钩子函数中通过 wrapperRef 对象访问高阶函数中的 div 元素,从而执行一些操作。

应用场景

结合上面的示例我们不难发现,forwardRef API 通常适用于以下两个场景:

  1. 通过 ref 对象访问子组件的 DOM 节点;
  2. 在高阶组件中使用 forwardRef

其实还可以在组件库中使用,比如我们熟知的 antd 中的 Modal 组件就提供了 ref 的访问能力。

由此我们知道,通过使用 forwardRef,我们可以轻松地将 ref 对象传递到子组件中,从而可以访问子组件的实例或者 DOM 节点,执行一些操作。

总结

简单回顾一下本文关于 forwardRef API 在 React 中的作用和使用方法:

  • forwardRef 可以用来访问子组件中的 DOM 节点或实例;
  • 在编写高阶组件时,forwardRef 能确保 ref 对象被正确的传递到被包装的组件中。

React 中的 forwardRef 是一个非常重要的 API,因为它能帮我们处理一些特殊场景,比如文中提到的访问子组件的 DOM 节点或者用于编写高阶组件。通过使用 forwardRef API,我们能更加方便的操作 React 组件,还能大大提高我们的开发效率。因此,掌握 React 中的 forwardRef 是非常非常必要的。如果不了解这个 API,比如要实现访问子组件 DOM 节点的需求,通过回调函数等方式实现的话将会非常之繁琐。

所以,你学会 forwardRef 了嘛~ 欢迎在下面留言讨论哦~~