👶
【React】(親から子|子から親)の関数を呼び出す
親から子の関数を呼び出す
実装方法としては、子供側の参照を親から触れるようにしてやり、
参照を通じて子供側の関数を呼び出せれるようにしてやります。
子供側の実装
const ChildrenBase: React.ForwardRefRenderFunction<
{ printId: () => void },
{
id: string;
}
> = ({ id }, ref) => {
// 親から呼ばれる関数を定義
useImperativeHandle(ref, () => ({
printId() {
console.log(id);
},
}));
return <div>Children</div>;
};
const Children = forwardRef(ChildrenBase);
forwardRefとuseImperativeHandleを使って実現します。
forwardRefでChildrenを参照し、useImperativeHandleで関数を参照に付与します。
親側の実装
const Parent: React.FC = () => {
const childRef = useRef<{ printId: () => void }>();
useEffect(() => {
childRef.current?.printId();
}, [childRef.current]);
return <Children id={'1234567'} ref={childRef} />;
};
export default Parent;
親側は参照を通して、子供側の関数を呼び出します。
子から親の関数を呼び出す
今度は逆のパターンで、子供側から親側の関数を呼び出すパターンです。
実装方法として、今回はpropsで渡す実装ではなく、全ての子供に親の関数を呼べるようにしてやります。
ユースケースとしては Layout
等の共通のコンポーネントで、子供が使おうと思ったら Layout
の関数が使える
ようなケースになるかと思います。
子供側の実装
type ChildrenDispatchProps = {
printId?: (id: string) => void;
};
const Children: React.FC<ChildrenDispatchProps & { id: string }> = ({
printId,
id,
}) => {
return <button onClick={() => printId(id)}>ボタン</button>;
};
親から渡される関数は ?
付きで定義しないとTypeエラーになります。
親側の実装
const Parent: React.FC = ({ children }) => {
const printId = (id: string) => {
console.log(id);
};
const childWithProps = React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
const dispatch: ChildrenDispatchProps = {
printId: printId,
};
return React.cloneElement(child, { ...dispatch });
}
return child;
});
return <div>{childWithProps}</div>;
};
const App: React.FC = () => {
return (
<Parent>
<Children id={'1'} />
<Children id={'2'} />
</Parent>
);
};
cloneElement
で子供に親側で定義した関数を付与してやります。
↑のようにする事で、子供側は ChildrenDispatchProps
を受け取るようにした場合、その子供は
親の関数 printId
を使えるようになります。
※ React.cloneElement
や React.isValidElement
等は以下リンク先を参照
React の最上位 API - React
Discussion