子コンポーネント内部の状態を変更する処理、例えば、FormikなどContext Apiを使用している処理を、その外側のコンポーネントから操作したい場合
親コンポーネントの関数を、props経由で子コンポーネントに渡すことは容易ですが、その逆はどのようにすればよいでしょうか?
解決方法
useImperativeHandle
というhookを使用すると、子コンポーネントを操作できる参照を親コンポーネントに渡すことができます。
実装
ものすごく簡単ですが、useState
の変数を表示するだけのコンポーネントを作成し、
その変数を操作する関数を、親コンポーネントに公開してみます
操作対象のコンポーネントを実装する
import {
useState,
ForwardRefRenderFunction,
forwardRef,
useImperativeHandle,
} from 'react'
export type ChildRefType = {
increment: () => void
clear: () => void
}
const Child: ForwardRefRenderFunction<ChildRefType> = (_, ref) => {
const [count, setCount] = useState(0);
useImperativeHandle(ref, () => ({
increment: () => setCount(v => v + 1),
clear: () => setCount(0)
}))
return (
<div>{count}</div>
)
}
export default forwardRef(Child)
この部分が、親コンポーネントに公開する操作の設定です。
increment
でカウントを進めて、clear
でカウントをクリアします。
useImperativeHandle(ref, () => ({
increment: () => setCount(v => v + 1),
clear: () => setCount(0)
}))
forwardRef
を使って、export
します。
export default forwardRef(Child)
親コンポーネントから子コンポーネントを操作する
作成した子コンポーネント(Child
)を操作する親コンポーネントの実装です。
import { FC, useRef } from 'react'
import Child, { ChildRefType } from './Child'
const Parent: FC = () => {
const childRef = useRef<ChildRefType>(null);
return (
<div>
<Child ref={childRef} />
<button onClick={() => childRef.current?.increment()}>increment</button>
<button onClick={() => childRef.current?.clear()}>clear</button>
</div>
);
}
export default Parent
これで、画面に表示されるincrement
ボタン、clear
ボタンを押下すると、
親コンポーネントから、子コンポーネントの内部状態であるuseState
を、公開した関数を通して操作が可能になっています