React组件父组件中调用子组件的方法

25 min read

在React组件中,经常需要直接访问DOM节点或在父组件中调用子组件的方法。forwardRefuseImperativeHandle 钩子使得这些操作成为可能。以下是如何使用这些技术的一个简单的讲解,包括一个示例代码和其对应的使用案例。

FancyInput 组件

首先,定义一个 FancyInput 组件,它使用 forwardRef 来接收一个传递给它的 ref

import React, { forwardRef, useRef, useImperativeHandle } from 'react';

const FancyInput = forwardRef((props, ref) => {
  // 创建一个ref来引用输入元素
  const inputRef = useRef();

  // 使用useImperativeHandle来指定希望暴露给父组件的实例值
  useImperativeHandle(ref, () => ({
    // 父组件可以调用的focus方法
    focus: () => {
      inputRef.current.focus();
    }
  }));

  // 将inputRef绑定到输入元素上,以便能够引用它
  return <input ref={inputRef} />;
});

在这段代码中,FancyInput 组件使用 useImperativeHandle 钩子来暴露一个 focus 方法给父组件。这个 focus 方法实际上调用了内部 input 元素的 focus 方法。

使用案例

现在,看一下如何在一个父组件中使用 FancyInput 组件:

import React, { useRef } from 'react';
import FancyInput from './FancyInput';

function ParentComponent() {
  // 创建一个ref来引用FancyInput组件
  const fancyInputRef = useRef();

  const onButtonClick = () => {
    // 当按钮被点击时,调用FancyInput组件的focus方法
    fancyInputRef.current.focus();
  };

  return (
    <div>
      <FancyInput ref={fancyInputRef} />
      <button onClick={onButtonClick}>Focus the input</button>
    </div>
  );
}

export default ParentComponent;

ParentComponent 中,我们创建了一个 reffancyInputRef),并将其传递给 FancyInput 组件。我们还有一个按钮,当点击时,会调用 FancyInput 组件的 focus 方法,这将使得输入框获得焦点。

通过这种方式,即使 FancyInput 内部的实现发生变化,只要 focus 方法保持不变,父组件都不需要做出任何更改。这就是使用 forwardRefuseImperativeHandle 可以提高组件封装性的一个例子。