はじめに
React で動画を操作する際、useRef と forwardRef を活用すると、コンポーネントをまたいで ref を渡し、動画の再生・停止・リセットをスムーズに制御できます。
本記事では、useRef と forwardRef を使用して、ボタンで動画の制御を行う方法を解説します。
この実装により、React の再レンダリングを抑えつつ、ユーザー操作による動画の管理が簡単にできるようになります。
動画プレイヤーをカスタマイズしたい場合や、再生状態をプログラムで制御したい場合に役立つテクニックです。
概要:forwardRefで別のコンポーネントのDOMノードにアクセス
自分で作ったコンポーネントに対してどうやってuseRefを関連付けることができるか
動画を再生・一時停止・リセットするシンプルな 動画プレイヤー を作成しています。
Page3_4.tsx でボタンを配置し、VideoPlayer.tsx で動画コンポーネントを定義しています。
実装準備:ページと動画を用意する
1. ページを作成

page.tsx
// Page3_4.tsx
"use client";
import * as React from "react";
import Typography from "@mui/material/Typography";
import { Button } from "@mui/material";
import { VideoPlayer } from "./VideoPlayer";
export default function Page3_4() {
// YouTubeの埋め込み用URLに変換
const videoSrc = "https://www.youtube.com/embed/7rka9b5wLmU";
return (
<div>
<Typography>Welcome to the Toolpad page3-4!</Typography>
<br />
<br />
<Button variant="outlined">Play</Button>
<Button variant="outlined">Pause</Button>
<Button variant="outlined">Reset</Button>
<br />
<br />
<VideoPlayer src={videoSrc} width="560" height="315" />
</div>
);
}
page3-4/VideoPlayer.tsx
// VideoPlayer.tsx
import { Card, CardContent, CardMedia } from '@mui/material';
import Typography from '@mui/material/Typography';
type VideoPlayerProps = {
width: string;
height: string;
src: string;
};
export const VideoPlayer = ({ width, height, src }: VideoPlayerProps) => {
return (
<div>
<Typography>YouTube video player</Typography>
<br />
<Card sx={{ maxWidth: 600 }}>
<CardMedia
component="video"
src="/page3-4/video/Zaha Hadid_Moon System 2007.mp4"
controls
/>
<CardContent>
<Typography variant="h6">Zaha Hadid Moon System 2007</Typography>
</CardContent>
</Card>
</div>
);
};
2. 動画を用意
今回は以前にiPadのお絵描きアプリでタイムラプスを使って作成したZaha HadidのMoon Systemを使用します。
自前の適当な動画がない方は以下からダウンロードしてください。
実装:手順と解説
1. VideoPlayer コンポーネントの作成 (VideoPlayer.tsx)
VideoPlayer.tsx では、動画を表示する 再利用可能なコンポーネント を作成します。
コードのポイント
forwardRefを使い、親コンポーネントから<video>を操作できるようにするCardMediaのcomponent="video"で MUI のCardに動画を埋め込むrefを<video>に適用 し、親コンポーネント (Page3_4.tsx) からplay() / pause() / currentTimeを操作可能にする。
VideoPlayer.tsx の流れ
- Props を受け取る (
width,height,src) forwardRefを使い、refを<video>に適用- MUI の
Cardを使ってデザインを整える
import { Card, CardContent, CardMedia } from '@mui/material';
import Typography from '@mui/material/Typography';
import { forwardRef } from 'react';
type VideoPlayerProps = {
width: string;
height: string;
src: string;
};
export const VideoPlayer = forwardRef<HTMLVideoElement, VideoPlayerProps>(
({ width, height, src }, ref) => {
return (
<div>
<Typography>Video player</Typography>
<br />
<Card sx={{ maxWidth: 600 }}>
<CardMedia
component="video"
src={src}
controls
sx={{ width, height }}
ref={ref} // ✅ ref を <video> に適用 (親コンポーネントから操作可能に)
/>
<CardContent>
<Typography variant="h6">Zaha Hadid Moon System 2007</Typography>
</CardContent>
</Card>
</div>
);
}
);
VideoPlayer.displayName = "VideoPlayer"; // ✅ 名前を設定 (デバッグ用)
2. Page3_4.tsx で動画プレイヤーを配置
このコンポーネントでは、ボタンで 動画を再生・一時停止・リセット する機能を実装します。
コードのポイント
useRef<HTMLVideoElement>を作成し、VideoPlayerの<video>を参照- ボタン (
Button) を使って、動画のplay() / pause() / currentTimeを制御 VideoPlayerにrefを渡し、親コンポーネントから制御
Page3_4.tsx の流れ
videoRefを作成し、<video>を参照- ボタンで動画を操作
VideoPlayerにrefを渡して動画を表示
"use client";
import * as React from "react";
import Typography from "@mui/material/Typography";
import { Button } from "@mui/material";
import { VideoPlayer } from "./VideoPlayer";
export default function Page3_4() {
// ✅ 動画要素を参照する useRef
const videoRef = React.useRef<HTMLVideoElement>(null);
const videoSrc = "/page3-4/video/Zaha Hadid_Moon System 2007.mp4";
// ✅ 最初に戻す処理
const handleReset = () => {
if (videoRef.current) {
videoRef.current.currentTime = 0; // ⬅️ 再生位置を 0 にリセット
videoRef.current.pause(); // ⬅️ 停止状態にする
}
};
return (
<div>
<Typography>Welcome to the Toolpad page3-4!</Typography>
<br />
<br />
{/* ✅ ボタンで動画を操作 */}
<Button onClick={() => videoRef.current?.play()} variant="outlined">
Play
</Button>
<Button onClick={() => videoRef.current?.pause()} variant="outlined">
Pause
</Button>
<Button onClick={handleReset} variant="outlined">
Reset
</Button>
<br />
<br />
{/* ✅ VideoPlayer を表示 (ref を渡す) */}
<VideoPlayer ref={videoRef} src={videoSrc} width="560" height="315" />
</div>
);
}
3. コンポーネント間の関係
| ファイル | 役割 |
|---|---|
VideoPlayer.tsx | 動画プレイヤー本体 (forwardRef を使用) |
Page3_4.tsx | ボタンで動画を制御する親コンポーネント (useRef で <video> を操作) |
Page3_4.tsxでuseRef<HTMLVideoElement>を作成VideoPlayer.tsxにrefを渡し、 を操作可能に- ボタン (
Button) で動画を制御
4. 動作確認
- ブラウザでページを開く
- ボタンをクリック
Play→ 動画が再生されるPause→ 動画が一時停止するReset→ 動画が最初に戻って停止する
- コンソールにエラーがないか確認
実装手順:まとめ
| 手順 | 内容 |
|---|---|
| 1 | VideoPlayer.tsx で forwardRef を使って <video> を参照可能にする |
| 2 | Page3_4.tsx で useRef を作成し、VideoPlayer に ref を渡す |
| 3 | Button で play() / pause() / currentTime = 0 を操作 |
| 4 | 動作確認 (Play / Pause / Reset ボタンをチェック) |
このように React の forwardRef + useRef を活用すると、親コンポーネントから子コンポーネントの要素を操作できます!
最終コード
page.tsx
// Page3_4.tsx
"use client";
import * as React from "react";
import Typography from "@mui/material/Typography";
import { Button } from "@mui/material";
import { VideoPlayer } from "./VideoPlayer";
export default function Page3_4() {
const videoRef = React.useRef<HTMLVideoElement>(null);
const videoSrc = "/page3-4/video/Zaha Hadid_Moon System 2007.mp4";
const handleReset = () => {
if (videoRef.current) {
videoRef.current.currentTime = 0; // 最初に戻る
videoRef.current.pause(); // 停止状態にする
}
}
return (
<div>
<Typography>Welcome to the Toolpad page3-4!</Typography>
<br />
<br />
<Button onClick={() => videoRef.current?.play()} variant="outlined">Play</Button>
<Button onClick={() => videoRef.current?.pause()} variant="outlined">Pause</Button>
<Button
onClick={handleReset}
variant="outlined"
>
Reset
</Button>
<br />
<br />
<VideoPlayer ref={videoRef} src={videoSrc} width="560" height="315"/>
</div>
);
}
VideoPlayer.tsx
// VideoPlayer.tsx
import { Card, CardContent, CardMedia } from '@mui/material';
import Typography from '@mui/material/Typography';
import { forwardRef } from 'react';
type VideoPlayerProps = {
width: string;
height: string;
src: string;
};
export const VideoPlayer = forwardRef<HTMLVideoElement, VideoPlayerProps>(
({ width, height, src }, ref) => {
return (
<div>
<Typography>Video player</Typography>
<br />
<Card sx={{ maxWidth: 600 }}>
<CardMedia
component="video"
src={src}
controls
sx={{ width, height }}
ref={ref} // ref を <video> に適用
/>
<CardContent>
<Typography variant="h6">Zaha Hadid Moon System 2007</Typography>
</CardContent>
</Card>
</div>
);
}
);
VideoPlayer.displayName = "VideoPlayer";
まとめ
useRef と forwardRef を活用することで、React コンポーネント間で ref を受け渡し、動画の操作を簡単に実装できました。本記事のポイントは以下の通りです。
useRefを使用すると、コンポーネントの再レンダリングを抑えつつ、DOM 要素への参照を保持できるforwardRefを利用することで、子コンポーネント (VideoPlayer) へrefを渡せるrefをvideo要素に適用し、play()・pause()・currentTimeを操作することで、ボタンで動画をコントロールできる
この方法を応用すれば、動画プレイヤーのカスタマイズや、アニメーション・スライドショーの制御など、さまざまな UI の実装が可能になります。ぜひ、自分のプロジェクトにも取り入れてみてください!