Reactのカスタムフックでタイマー・カウントダウンを管理する方法!初心者でもわかるReact Hooks入門
生徒
「Reactでタイマーやカウントダウンを作りたいです。でも同じ処理を何度も書くのは大変です。」
先生
「その場合は『カスタムフック』を作ると便利です。処理を一箇所にまとめて再利用できます。」
生徒
「カスタムフックなら、タイマーの開始や停止も簡単に管理できるんですか?」
先生
「はい、では実際にどのように作るか見ていきましょう。」
1. タイマーをカスタムフックで管理するメリット
Reactではタイマーやカウントダウンを管理する場合、setIntervalやsetTimeoutを使います。これをコンポーネントごとに書くと、同じ処理が複数箇所に重複してしまいます。
カスタムフックを作ると、タイマー処理を一箇所にまとめ、どのコンポーネントからも呼び出せるようになります。
例えば、ゲームのカウントダウンや通知のタイマーなど、再利用したい場面でとても便利です。
2. タイマー用のカスタムフックを作る
まず、タイマーやカウントダウンを管理するカスタムフックを作ります。
import { useState, useEffect, useRef } from "react";
function useTimer(initialSeconds) {
const [seconds, setSeconds] = useState(initialSeconds);
const [isActive, setIsActive] = useState(false);
const intervalRef = useRef(null);
const start = () => setIsActive(true);
const pause = () => setIsActive(false);
const reset = () => setSeconds(initialSeconds);
useEffect(() => {
if (isActive) {
intervalRef.current = setInterval(() => {
setSeconds(prev => {
if (prev <= 0) {
clearInterval(intervalRef.current);
return 0;
}
return prev - 1;
});
}, 1000);
} else {
clearInterval(intervalRef.current);
}
return () => clearInterval(intervalRef.current);
}, [isActive]);
return { seconds, isActive, start, pause, reset };
}
export default useTimer;
このフックでは、タイマーの残り時間をsecondsで管理し、startで開始、pauseで停止、resetで初期値に戻せます。
useRefを使うことで、コンポーネントが再レンダリングされても同じタイマーIDを保持できます。
3. カスタムフックを使ったコンポーネント例
次に、先ほど作ったuseTimerを使ってカウントダウンを表示する例です。
import React from "react";
import useTimer from "./useTimer";
function Countdown() {
const { seconds, isActive, start, pause, reset } = useTimer(10);
return (
<div>
<h1>残り時間: {seconds}秒</h1>
<button onClick={start}>スタート</button>
<button onClick={pause}>一時停止</button>
<button onClick={reset}>リセット</button>
</div>
);
}
export default Countdown;
カスタムフックを使うことで、タイマーの状態管理やボタン操作のロジックがコンポーネントから分離され、コードがすっきりします。
4. カスタムフックの応用例
このカスタムフックは、単純なカウントダウンだけでなく、複数のタイマーやゲームの残り時間、アンケートの制限時間などにも応用できます。
さらに、タイマーが0になったときにイベントを発火させる処理を追加すると、通知やアラートにも活用できます。
useEffect(() => {
if (seconds === 0) {
alert("時間切れです!");
}
}, [seconds]);
このように、カスタムフックを活用するとタイマー関連の処理を一箇所にまとめて、再利用性の高いコードを書くことができます。
5. ポイント整理
Reactでタイマーやカウントダウンを作る場合、useStateやuseEffectを使うのが基本です。
カスタムフックにまとめることで、コンポーネントがシンプルになり、処理を再利用できるので開発効率が上がります。
タイマーの開始・停止・リセットの操作や、0秒になったときの処理もカスタムフックに含めることができます。
まとめ
Reactでタイマーやカウントダウンを管理する方法を学んできましたが、あらためて振り返ってみると、カスタムフックという仕組みがいかに便利で強力であるかがよくわかります。タイマーやカウントダウンは、ゲームや学習アプリ、タスク管理ツールなど、多くのアプリケーションに欠かせない要素です。しかし、そのたびに毎回同じような処理を書いていては、コードは複雑になり、管理が難しくなってしまいます。カスタムフックを使えば、複雑なロジックを一箇所にまとめ、何度でも再利用できる美しい仕組みが作れます。
また、今回の解説を通じて、useStateで状態を管理し、useEffectで時間の経過を監視し、useRefでタイマーIDを保持するという、React Hooksの基本的な役割を自然に理解できたはずです。特に、コンポーネントが再描画されても変わらない値を保持できるuseRefの特性は、タイマー処理との相性がよく、初心者でも扱いやすいポイントです。こうしたReact Hooksの特徴を体験していくと、実際の開発でも困らずに複雑な動きを管理できるようになります。
さらに、タイマーが0になったときのイベント処理や、複数のタイマーを同時に管理するなど、さまざまな応用例も紹介しました。これにより、単なるカウントダウン機能にとどまらず、アプリ全体に広がる動的な動きを作り出す基盤が整います。カスタムフックを使った開発は、コードの重複を減らし、アプリケーションの見通しを良くし、メンテナンス性を高める大きな効果があります。
理解を深めるミニサンプル:カスタムフックで簡単リピートタイマー
最後に、今回学んだ内容をさらに深めるため、一定時間ごとにメッセージを更新する簡単なタイマーのサンプルを紹介します。カスタムフックを使えば、タイマーが止まったり再開したりする動きを柔軟に扱えます。
import { useState, useEffect, useRef } from "react";
function useRepeatTimer(interval) {
const [count, setCount] = useState(0);
const [running, setRunning] = useState(false);
const timerRef = useRef(null);
const start = () => setRunning(true);
const stop = () => setRunning(false);
useEffect(() => {
if (running) {
timerRef.current = setInterval(() => {
setCount(prev => prev + 1);
}, interval);
} else {
clearInterval(timerRef.current);
}
return () => clearInterval(timerRef.current);
}, [running]);
return { count, start, stop };
}
このミニサンプルは、一定間隔でカウントが増えていくタイマーを表しています。React Hooksの動きがより直感的に理解でき、実際のアプリケーションに取り入れやすい構造になっています。学んだ内容をそのまま活用できるので、ぜひ試してみてください。
生徒
「先生、タイマーのしくみがすごくよくわかりました!カスタムフックってこんなに便利なんですね。」
先生
「そうなんです。繰り返し使う処理はカスタムフックにまとめると、とても管理しやすくなります。今回のタイマーはその良い例ですね。」
生徒
「たしかに、start・pause・resetを一つのファイルにまとめるだけで、コンポーネントのコードがスッキリして読みやすくなりました!」
先生
「その通り。コードの再利用性が高くなると、開発が楽になるだけでなく、バグも減ります。ReactのHooksはこうした管理を得意としています。」
生徒
「これならゲームの制限時間やクイズの制限時間、通知のタイマーも作れそうです!」
先生
「もちろん作れますよ。ぜひ今回のカスタムフックを基礎にして、実践的なアプリも作ってみましょう。」
生徒
「はい!Reactでできることがどんどん増えてきて楽しいです!」