🌟
Reactで親コンポーネントから子コンポーネントのメソッドを実行する方法
基本は親コンポーネントが子コンポーネントのメソッドを実行したくなったら、何か設計を誤っている可能性が高い。まずはそこを考えることが重要。
が、汎用コンポーネントなどで親から子コンポーネントのメソッドを実行したくなるケースも無くはない。そういう場合どうするのか?
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