返回

函数式组件之ref解决方案:在 Hooks 中保存引用

前端

对于 React 中需要强制修改子组件的情况,React 提供了 Refs 这种解决办法,使得我们可以操作底层 DOM 元素或者自定的 class 组件实例。除此之外,文档(v17.0.1)对函数式组件另有不能在函数式组件上使用ref属性,因为他们没有实例。

在函数式组里,想要给子元素添加一个引用,我们没有办法直接给他挂载一个ref,因为它会报错。但是我们可以把 ref 的值放入一个父组件的变量之中。以下是使用 Hooks 来保存引用的步骤:

  1. 使用 useCallback 创建一个引用函数。
  2. 将引用函数作为回调函数传递给子组件。
  3. 在子组件中,将引用函数用于 useEffectuseImperativeHandle 中。
// 父组件
const Parent = () => {
  const ref = useRef();

  const setRef = useCallback((node) => {
    ref.current = node;
  }, []);

  return (
    <div>
      <Child ref={setRef} />
    </div>
  );
};

// 子组件
const Child = React.forwardRef((props, ref) => {
  useEffect(() => {
    // 在组件挂载时,将 ref 的值存储在当前组件的实例中。
    ref.current = ReactDOM.findDOMNode(this);
  }, []);

  return <div>我是子组件</div>;
});

useCallback 用于创建引用函数,并且当 ref 的值改变时,会返回一个新的引用函数。因此,在父组件中,useCallback 的第二个参数是一个空数组,这表明引用函数在整个组件的生命周期中保持不变。

useRef 用于创建一个引用对象,并将其存储在父组件的状态中。引用对象是可变的,因此我们可以通过 ref.current 来访问底层的 DOM 元素或组件实例。

将引用函数作为回调函数传递给子组件,使子组件能够访问该函数。在子组件中,将引用函数用于 useEffectuseImperativeHandle 中,以便在组件挂载时将 ref 的值存储在组件的实例中。

需要注意的是,在函数式组件中,我们不能使用 this 来访问组件的实例,因此我们需要使用 useImperativeHandle 来暴露一个公共的 API。

这样,我们就可以在函数式组件中使用 ref 来操作子组件了。