React Hooks ∋ useImperativeHandle

useRefと同じ様な使用用途です。useRefはコンポーネント内の HTML 要素を触る為のフックでしたが、useImperativeHandle親コンポーネントにコンポーネント内の要素を触る為の手段を提供する為のフックです。React.forwardRefとの違いは2つほどあると思います。

  1. コンポーネント内の要素を親コンポーネントから直接触られない
  2. コンポーネント内の複数の要素(参照)を親コンポーネントは触ることができる

例。このフックは親参照をもらうためにforwardRefと共に使います。

const Checkbox = forwardRef((_, ref) => {
  const checkboxRef = useRef(null);

  useImperativeHandle(ref, () => ({
    check() {
      if (checkboxRef.current !== null) {
        checkboxRef.current.checked = true;
      }
    }
  }));

  return <input ref={checkboxRef} type="checkbox" />;
});

forwardRefによって親コンポーネントからrefが渡ってくる想定です。useImperativeHandleはこのref.currentにハンドラーを生やします。この例ではcheckメソッドを持つオブジェクトを返していますが、これがまさにref.current.checkを実装していることになります。
この中のuseRefは普段通りに使うだけです。

親コンポーネントからref.current.check()が呼ばれるとコンポーネント内のinput[type=checkbox]のチェックフラグをtrueに書き換えてます。(React にはもっと優れた方法があるので実際にはこのように実装しないように)

親コンポーネント

さて、親です。親では何度も言っているref.current.check()の実行の仕組みとハンドラーを生やすためのrefforwardRefなコンポーネントに渡す必要があります。

export default () => {
  const ref = React.useRef();
  const onClick = React.useCallback(() => {
    ref.current.check();
  }, []);

  return (
    <div className="App">
      <Checkbox ref={ref} />
      <button onClick={onClick}>check!</button>
    </div>
  );
};

useRefでは要素が存在しない場合があるので、初期値をnullとしてましたが今回は必ずハンドラーが入るので初期値は要りません。

check!ボタンを押してinput[type=checkbox]にチェックが入るか確認できたら完了です。