Reactでストップウォッチを作る理由
時間を扱うアプリの重要性とは?
結論:ストップウォッチはReactの基本スキルを学ぶ絶好の題材です。
以下のようなシーンで時間の計測が使われています。
- 運動記録(ランニングタイマーなど)
- 勉強時間の管理(ポモドーロ式など)
- 工場や業務現場での作業時間測定
- 子どものゲームや遊び時間の制限
こうした「時間を測る機能」は、Webアプリだけでなく実社会でも広く使われています。
Reactでストップウォッチを作ることで、画面の状態管理・時間制御・副作用の扱いなど、多くのスキルが身につきます。
useRefとuseEffectの使い分け
useRefはなぜ必要なのか?
結論:画面の再描画を避けつつ、値を保持するために使います。
通常の状態管理(useState)は値が変わるたびに画面が更新されます。
しかし、ストップウォッチでは、1秒ごとに状態を更新すると負荷が高くなります。
そのため、useRefを使って「再描画しないが保持される値」として時間やタイマーIDを記録します。
useEffectはどこで使う?
結論:初期化やクリーンアップなど、タイミングを調整するために使います。
useEffectは以下のような処理に適しています。
- アプリ起動時に処理を1度だけ実行
- コンポーネントが破棄されるときにタイマーを止める
- ボタン押下に応じてイベントを切り替える
ストップウォッチのように時間と密接に関わる機能では、useEffectの使い方が非常に重要です。
Reactでストップウォッチの表示を作る
画面とボタンの構成を考える
結論:シンプルに「時間」と「3つのボタン」を用意します。
以下が基本の構成です:
- 経過時間の表示(00:00:00)
- スタートボタン
- ストップボタン
- リセットボタン
function Stopwatch() {
const [time, setTime] = useState(0); // 経過時間(秒)
const timerRef = useRef(null);
return (
<div>
<h2>ストップウォッチ</h2>
<h1>{formatTime(time)}</h1>
<button>スタート</button>
<button>ストップ</button>
<button>リセット</button>
</div>
);
}
function formatTime(seconds) {
const h = String(Math.floor(seconds / 3600)).padStart(2, '0');
const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0');
const s = String(seconds % 60).padStart(2, '0');
return `${h}:${m}:${s}`;
}
スタート・ストップ・リセット機能の実装
実際の動きをReactで表現する
結論:setIntervalで時間を進め、useRefで管理すれば簡単に実現できます。
function Stopwatch() {
const [time, setTime] = useState(0);
const timerRef = useRef(null);
const start = () => {
if (timerRef.current !== null) return;
timerRef.current = setInterval(() => {
setTime((prev) => prev + 1);
}, 1000);
};
const stop = () => {
clearInterval(timerRef.current);
timerRef.current = null;
};
const reset = () => {
stop();
setTime(0);
};
useEffect(() => {
return () => clearInterval(timerRef.current); // アンマウント時に停止
}, []);
return (
<div>
<h2>ストップウォッチ</h2>
<h1>{formatTime(time)}</h1>
<button onClick={start}>スタート</button>
<button onClick={stop}>ストップ</button>
<button onClick={reset}>リセット</button>
</div>
);
}
応用機能と改良ポイント
さらに良いストップウォッチにするには?
結論:以下のような追加機能でより実用的になります。
- 一時停止と再開機能
- ラップタイム(区切り時間)の記録
- CSSで見た目を改善
- 時間の最大値やアラームの設定
時間や副作用の処理を学ぶのにちょうど良い題材として、ストップウォッチは非常におすすめです。
完成形コード一覧
import React, { useState, useRef, useEffect } from 'react';
function Stopwatch() {
const [time, setTime] = useState(0);
const timerRef = useRef(null);
const start = () => {
if (timerRef.current !== null) return;
timerRef.current = setInterval(() => {
setTime((prev) => prev + 1);
}, 1000);
};
const stop = () => {
clearInterval(timerRef.current);
timerRef.current = null;
};
const reset = () => {
stop();
setTime(0);
};
useEffect(() => {
return () => clearInterval(timerRef.current);
}, []);
return (
<div>
<h2>ストップウォッチ</h2>
<h1>{formatTime(time)}</h1>
<button onClick={start}>スタート</button>
<button onClick={stop}>ストップ</button>
<button onClick={reset}>リセット</button>
</div>
);
}
function formatTime(seconds) {
const h = String(Math.floor(seconds / 3600)).padStart(2, '0');
const m = String(Math.floor((seconds % 3600) / 60)).padStart(2, '0');
const s = String(seconds % 60).padStart(2, '0');
return `${h}:${m}:${s}`;
}
export default Stopwatch;
まとめ
ReactのuseRef
とuseEffect
を使って、ストップウォッチアプリをゼロから作る方法を学んできました。
おさらいとして:
- useRefは再描画せずに値を保持する道具
- useEffectは処理の開始・終了タイミングを管理する手段
- Reactを使えば、誰でも本格的なストップウォッチが作れる
ぜひ実際にコードを試しながら、Reactの「時間」と「状態」の扱い方に慣れてみてください。
関連リンク: