🌟

Reactで親コンポーネントから子コンポーネントのメソッドを実行する方法

2024/02/20に公開

基本は親コンポーネントが子コンポーネントのメソッドを実行したくなったら、何か設計を誤っている可能性が高い。まずはそこを考えることが重要。

が、汎用コンポーネントなどで親から子コンポーネントのメソッドを実行したくなるケースも無くはない。そういう場合どうするのか?

useImperativeHandleを利用する

useImperativeHandle は ref として公開されるハンドルをカスタマイズするための React フック。ref は DOMノードを操作するために利用されるが、用途は他にも色々ある。DOMノードではなくオブジェクトの保存にも利用することが可能。その特性を利用する。

親コンポーネント

  • childRefを設定。ここに子コンポーネントのメソッドを登録する。よくやるのはここにHTMLDIVElementなどを設定するが今回はオブジェクトを設定する。
  • 親コンポーネント側でボタンをクリックすると子コンポーネントのメソッドを実行する。
import { useRef } from "react";

import Child, { ChildMethods } from "./Child";

function Parent() {
  const childRef = useRef<ChildMethods | null>(null);

  const handleClick = () => {
    childRef.current?.hello();
  };

  return (
    <div>
      <h1>Parent</h1>
      <Child ref={childRef} />
      <button type="button" onClick={handleClick}>
        Childのメソッドを実行
      </button>
    </div>
  );
}

export default Parent;

子コンポーネント

  • この子コンポーネントは forwardRef を使って ref を受け入れるコンポーネントとして宣言。
  • useImperativeHandle を使って親コンポーネントにカスタムrefハンドルを公開する。
  • useImperativeHandle 内で設定したメソッドは、コンポーネント内のステートも参照できることを確認。
import { forwardRef, useImperativeHandle, useState } from "react";

export interface ChildMethods {
  hello: () => void;
}

const Child = forwardRef((_, ref) => {
  const [count, setCount] = useState(0);

  useImperativeHandle(ref, () => ({
    hello() {
      console.log("Hello from Child", count);
    },
  }));

  return (
    <div>
      <h1>Child</h1>
      <button
        type="button"
        onClick={() => {
          setCount((prev) => prev + 1);
        }}
      >
        child button
      </button>
    </div>
  );
});

export default Child;

ref の利用パターンは他にも色々あると思うので特性を知って活用するとコードの幅が広がる。

株式会社トゥーアール

Discussion