Reactでストップウォッチを作る理由
時間を扱うアプリの重要性とは?
結論:ストップウォッチはReactの基本スキルを学ぶ絶好の題材です。
以下のようなシーンで時間の計測が使われています。
- 運動記録(ランニングタイマーなど)
- 勉強時間の管理(ポモドーロ式など)
- 工場や業務現場での作業時間測定
- 子どものゲームや遊び時間の制限
こうした「時間を測る機能」は、Webアプリだけでなく実社会でも広く使われています。
Reactでストップウォッチを作ることで、画面の状態管理・時間制御・副作用の扱いなど、多くのスキルが身につきます。
useRefとuseEffectの使い分け
useRefはなぜ必要なのか?
結論:画面の再描画を避けつつ、値を保持するために使います。
通常の状態管理(useState)は値が変わるたびに画面が更新されます。
しかし、ストップウォッチでは、1秒ごとに状態を更新すると負荷が高くなります。
そのため、useRefを使って「再描画しないが保持される値」として時間やタイマーIDを記録します。
useEffectはどこで使う?
結論:初期化やクリーンアップなど、タイミングを調整するために使います。
useEffectは以下のような処理に適しています。
- アプリ起動時に処理を1度だけ実行
- コンポーネントが破棄されるときにタイマーを止める
- ボタン押下に応じてイベントを切り替える
ストップウォッチのように時間と密接に関わる機能では、useEffectの使い方が非常に重要です。
Reactでストップウォッチの表示を作る
画面とボタンの構成を考える
結論:シンプルに「時間」と「3つのボタン」を用意します。
以下が基本の構成です:
- 経過時間の表示(00:00:00)
- スタートボタン
- ストップボタン
- リセットボタン
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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で管理すれば簡単に実現できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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で見た目を改善
- 時間の最大値やアラームの設定
時間や副作用の処理を学ぶのにちょうど良い題材として、ストップウォッチは非常におすすめです。
完成形コード一覧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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の「時間」と「状態」の扱い方に慣れてみてください。
関連リンク: