< 카운트 다운 소스 >
import React, { Fragment, useState, useEffect, useRef } from "react";
function Solution() {
// 분, 초 카운트 제어용
const [inputM, setInputM] = useState(0);
const [inputS, setInputS] = useState(0);
const [m, setM] = useState("00");
const [s, setS] = useState("00");
// 타이머 고유ID 저장
const countTimerRef = useRef();
// 이전 클로저 함수 저장
const oldTimerRef = useRef();
// 일시정지 관리
const [pauseFlag, setPauseFlag] = useState(false);
// 메인 카운트다운
const counter = () => {
const countData = { minute: null, second: null };
return (minute, second) => {
countData.minute = countData.minute === null ? minute : countData.minute;
countData.second = countData.second === null ? second : countData.second;
countTimerRef.current = setInterval(function () {
if (countData.minute === 0 && countData.second === 0) {
clearInterval(countTimerRef.current);
return;
}
const minute = countData.minute > 0 && countData.second === 0
? countData.minute - 1
: countData.minute;
const second = countData.second === 0 ? 59 : countData.second - 1;
countData.minute = minute;
countData.second = second;
setM(minute < 10 ? "0" + minute : minute);
setS(second < 10 ? "0" + second : second);
}, 1000);
};
};
// START 버튼 클릭
const startClick = () => {
// 분, 초 값 정리
const minutes = Number(inputM) + parseInt(Number(inputS) / 60);
const seconds = Number(inputS) % 60;
setM(minutes < 10 ? "0" + minutes : minutes);
setS(seconds < 10 ? "0" + seconds : seconds);
// 비동기 useState 때문에 closure 함수로 사용
const start = counter();
oldTimerRef.current = start;
start(minutes, seconds);
};
// PAUSE / RESUME 버튼 클릭
const pAndRClick = () => {
setPauseFlag(!pauseFlag);
};
// 일시정지 처리용
useEffect(() => {
if (pauseFlag) clearInterval(countTimerRef.current);
else if (oldTimerRef.current) {
oldTimerRef.current();
}
}, [pauseFlag]);
// RESET 버튼 클릭
const resetClick = () => {
clearInterval(countTimerRef.current);
setInputM(0);
setInputS(0);
setM("00");
setS("00");
};
return (
<Fragment>
<label>
<input
type="number"
onChange={(e) => setInputM(e.target.value)}
value={inputM}
/>
Minutes
</label>
<label>
<input
type="number"
onChange={(e) => setInputS(e.target.value)}
value={inputS}
/>
Seconds
</label>
<button onClick={startClick}>START</button>
<button onClick={pAndRClick}>PAUSE / RESUME</button>
<button onClick={resetClick}>RESET</button>
<h1 data-testid="running-clock">
{m}:{s}
</h1>
</Fragment>
);
}
export default Solution;