Hooked.
← Hooked.

useImperativeHandle

公式ドキュメント ↗
DOM要素をそのまま渡さない理由
// DOM要素をそのまま渡す場合、親は何でもできてしまう
<input ref={parentRef} />;
parentRef.current.value = "直接書き換え"; // Reactのstateを介さない変更
parentRef.current.remove(); // DOMから消してしまうことも可能
parentRef.current.style.color = "red"; // スタイルも自由に触れる

// useImperativeHandleなら、公開する操作を自分で絞り込める
useImperativeHandle(ref, () => ({
  focus: () => inputRef.current?.focus(),
  clear: () => {
    /* Reactの管理下で安全にクリア */
  },
}));

input要素そのものをrefで親へ渡すこともできるが、それでは親にできることが広がりすぎることがある。子コンポーネントの中身(DOM構造やライブラリの詳細)を隠しつつ、親が本当に必要な操作だけを安全に公開できる。中身を後から作り替えても、公開した操作さえ変えなければ親のコードは壊れない。

注意点: あくまで最後の手段として使う

「親が子に命令する」ような書き方は、Reactの「状態が変わったら画面が描き直される」という基本のスタイルから外れた、いわば非常口(脱出ハッチ)。propsやstateで表現できるなら、そちらを優先した方がコンポーネント同士のつながりが緩くなる。フォーカス制御、スクロール位置の調整、このデモのシェイクのような一時的なアニメーションのトリガーなど、propsやstateでは表現しづらい操作に限って使うのがおすすめ。