useImperativeHandle(ref, createHandle, dependencies?)
interface InputHandle {
focus: () => void;
clear: () => void;
}
const Input = forwardRef<InputHandle, Props>((props, ref) => {
useImperativeHandle(ref, () => ({ focus, clear }));
...
});import { useRef, useImperativeHandle, forwardRef } from 'react';
// ── 問題: ref は通常 DOM 要素しか参照できない ─────────
// 子コンポーネントのメソッドを親から呼びたい場合に使う
// ── Step1: 公開するメソッドの型を定義 ────────────────
type VideoPlayerHandle = {
play: () => void;
pause: () => void;
seek: (seconds: number) => void;
};
// ── Step2: forwardRef + useImperativeHandle で実装 ─────
const VideoPlayer = forwardRef<VideoPlayerHandle>((props, ref) => {
const videoRef = useRef<HTMLVideoElement>(null);
// 親に公開するメソッドを定義
useImperativeHandle(ref, () => ({
play: () => videoRef.current?.play(),
pause: () => videoRef.current?.pause(),
seek: (seconds) => {
if (videoRef.current) videoRef.current.currentTime = seconds;
},
}));
return <video ref={videoRef} src="/movie.mp4" />;
});
// ── Step3: 親から子のメソッドを呼ぶ ─────────────────
function App() {
const playerRef = useRef<VideoPlayerHandle>(null);
return (
<div>
<VideoPlayer ref={playerRef} />
{/* 親から子のメソッドを直接呼べる */}
<button onClick={() => playerRef.current?.play()}>再生</button>
<button onClick={() => playerRef.current?.pause()}>停止</button>
<button onClick={() => playerRef.current?.seek(30)}>30秒へ</button>
</div>
);
}useImperativeHandleは命令的なAPIが本当に必要な場合(アニメーション・フォーカス管理等)に限定して使う。通常は状態やpropsで制御する方がReactらしい設計。