はじめに
Reactにおいてコンポーネント間のメソッド実行はReduxなど使ってやるのが一般的ですが、
さくっとつくりたいアプリケーションにReduxは荷が重いです。
また、子が親のメソッドを実行するのはpropsで受け取った関数を呼べば良いだけですが、
親が子のメソッドを実行するのは意外と面倒みたいです。(なかなか調べても出てこない)
サンプル
今回のサンプルはuseRef, useImperativeHandle, forwardRefを使って子メソッドの実行を実現しています。
codesandboxにコピペしてmaterial-uiをADDすればすぐ動きます
import React, { useState, useRef, useImperativeHandle, forwardRef } from "react";
import Button from "@material-ui/core/Button";
export default function Parent() {
const parentAdd = () => {
Children.current.plus()
console.log('親です')
}
return (
<div>
<Children parentAdd={parentAdd} ref={Children}/>
<Button onClick={parentAdd}>親add</Button>
</div>
);
}
let Children = (props, ref) => {
const [state, setState] = useState(1);
const inputRef = useRef()
useImperativeHandle(ref, () => ({
plus: () => {
plus()
}
}))
const plus = () => {
setState(state + 1);
};
return (
<div ref={inputRef}>
<div>{state}</div>
<Button onClick={plus}>子add</Button>
</div>
);
};
Children = forwardRef(Children)
動き
親と子どちらのボタンを押しても数字が反応します。
親の持ち物
・子のplus()を実行する「親addボタン」←これがやりたいこと
・子
子の持ち物
・数字の描画
・数字をインクリメントする関数plus()を実行する「子addボタン」
注意
コンソールに以下のWarningが出るのでご注意ください。
Warning: Expected useImperativeHandle() first argument to either be a ref callback or React.createRef() object. Instead received: an object with keys {$$typeof, render}.