現状:
エンジニアへの未経験転職。
就職先も決まり、2月からひよこエンジニアに。
内容は常に書き散らしのメモです、あしからず。
当面の目標:LPIC101,102合格
React
ストップウォッチコンポーネントの作成
-
ストップウォッチ
import { useState, useEffect, useRef } from "react"; const StopWatch: React.FC = () => { const [time, setTime] = useState(0); const [isRunning, setIsRunning] = useState(false); const timerRef = useRef<number | null>(null); useEffect(() => { if (isRunning) { timerRef.current = window.setInterval(() => { setTime((prevTime) => prevTime + 10); }, 10); } else { if (timerRef.current !== null) { clearInterval(timerRef.current); timerRef.current = null; } } return () => { if (timerRef.current !== null) { clearInterval(timerRef.current); timerRef.current = null; } }; }, [isRunning]); const formatTime = (milliseconds: number) => { const minutes = Math.floor(milliseconds / 60000); const seconds = Math.floor((milliseconds % 60000) / 1000); const ms = Math.floor((milliseconds % 1000) / 10); return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart( 2, "0" )}:${String(ms).padStart(2, "0")}`; }; return ( <> <div className="p-4 max-w-sm mx-auto border rounded-lg shadow-md text-center"> <h2 className="text-xl font-semibold mb-2">StopWatch</h2> <div className="text-3xl font-mono p-4 border rounded bg-gray-100"> {formatTime(time)} </div> <div className="mt-4 space-x-2"> <button className={`px-4 py-3 text-white rounded ${ isRunning ? "bg-red-500 hover:bg-red-600" : "bg-green-500 hover:bg-green-600" }`} onClick={() => setIsRunning(!isRunning)} > {isRunning ? "Stop" : "Start"} </button> <button className="px-4 py-2 bg-gray-500 text-white rounded hober:bg-gray-600" onClick={() => { setTime(0); }} > reset </button> </div> </div> </> ); }; export default StopWatch;
-
解説(ChatGPT)
コードの詳細解説:StopWatch コンポーネント
-
1. import 文
import { useState, useEffect, useRef } from "react";
React の フック (Hook) を3つインポートしています。
• useState:コンポーネントの状態 (time と isRunning) を管理
• useEffect:副作用(ストップウォッチの動作)を設定
• useRef:setInterval の ID を管理(クリーンアップ用)
-
2. コンポーネントの定義
const StopWatch: React.FC = () => {
この行で React 関数コンポーネント を定義しています。
React.FC
は「このコンポーネントは Props を受け取らない」という型指定。 -
3. 状態の定義
const [time, setTime] = useState(0);
• time:ストップウォッチの 経過時間 (ミリ秒単位)
• setTime:time の更新関数
• 初期値は 0(ストップウォッチは 0 秒からスタート)
const [isRunning, setIsRunning] = useState(false);
• isRunning:ストップウォッチの 動作状態 (true:動作中, false:停止中)
• setIsRunning:isRunning の更新関数
• 初期値は false(ストップウォッチは停止状態)
const timerRef = useRef<number | null>(null);
• timerRef:setInterval の ID を保持(clearInterval のために使用)
• 初期値は null
-
4. ストップウォッチの動作管理 (useEffect)
useEffect(() => { if (isRunning) { timerRef.current = window.setInterval(() => { setTime((prevTime) => prevTime + 10); }, 10); } else { if (timerRef.current !== null) { clearInterval(timerRef.current); timerRef.current = null; } } return () => { if (timerRef.current !== null) { clearInterval(timerRef.current); timerRef.current = null; } }; }, [isRunning]);
動作の流れ
- isRunning が true の場合
• setInterval を 10ms ごとに実行
• setTime で time を 10ms ずつ増加
• timerRef.current に setInterval の ID を保存
- isRunning が false の場合
• clearInterval で setInterval を停止
• timerRef.current を null にリセット
- クリーンアップ処理 (return の関数)
• コンポーネントがアンマウントされる又は isRunning が変更される時
• clearInterval を実行し、タイマーを確実に停止
-
5. 時間のフォーマット
const formatTime = (milliseconds: number) => { const minutes = Math.floor(milliseconds / 60000); const seconds = Math.floor((milliseconds % 60000) / 1000); const ms = Math.floor((milliseconds % 1000) / 10); return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart( 2, "0" )}:${String(ms).padStart(2, "0")}`; };
動作の流れ
-
milliseconds(ミリ秒単位の数値)を受け取る
-
分 (minutes) を計算
• 60000ms = 1分 なので milliseconds / 60000
- 秒 (seconds) を計算
• 60000ms 単位の余りを 1000ms で割る
- ミリ秒 (ms) を計算
• 1000ms の余りを 10ms で割る(00 ~ 99 の範囲に調整)
- padStart(2, "0") で 常に2桁表示
例
formatTime(75420) // "01:15:42"(1分15秒42ミリ秒)
-
-
6. コンポーネントの JSX
<> <div className="p-4 max-w-sm mx-auto border rounded-lg shadow-md text-center"> <h2 className="text-xl font-semibold mb-2">StopWatch</h2> <div className="text-3xl font-mono p-4 border rounded bg-gray-100"> {formatTime(time)} </div> <div className="mt-4 space-x-2">
• div で コンポーネント全体を囲む
• h2 で タイトル「StopWatch」
• div で ストップウォッチの時間を表示
• formatTime(time) を適用し、00:00:00 の形式 で表示
• Tailwind CSS を使用し、デザインを整える
-
7. スタート / ストップ ボタン
<button className={`px-4 py-3 text-white rounded ${ isRunning ? "bg-red-500 hover:bg-red-600" : "bg-green-500 hover:bg-green-600" }`} onClick={() => setIsRunning(!isRunning)} > {isRunning ? "Stop" : "Start"} </button>
• isRunning が true なら 「Stop」ボタン
• false なら 「Start」ボタン
• onClick={() => setIsRunning(!isRunning)} で ボタンのクリック時に状態を切り替え
• bg-red-500 / bg-green-500 で 状態に応じて色を変化
-
8. リセット ボタン
<button className="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600" onClick={() => { setIsRunning(false); setTime(0); }} > reset </button>
• onClick 時に ストップウォッチを停止 (isRunning = false)
• setTime(0) で 時間を 0 にリセット
• bg-gray-500 で デザインを調整
-
9. エクスポート
export default StopWatch;
• export default で コンポーネントを外部で使用できるようにする
まとめ
✅ useState で 時間と動作状態を管理
✅ useEffect で setInterval の開始・停止を制御
✅ useRef で setInterval の ID を保持し、適切にクリア
✅ formatTime() で 時間を「00:00:00」形式に変換
✅ button で スタート / ストップ / リセットを制御
✅ Tailwind CSS で デザインを整える
-
-