useRef는 DOM을 선택하는 기능뿐만 아니라, 리랜더링되어도 초기화되지 않는 변수를 관리할 수 있습니다.
이러한 특징을 이용해 스톱워치를 만들어 보겠습니다.
1) 선언
function StopWatch(){
//ref 객체
const timeRef = useRef(null);
//start 작동 여부 판별할 state
const [isStartOperation,setIsStartOperation]=useState(false);
//경과 시간 state
const [count,setCount]=useState(0);
시간 증가와 관련있는 timeRef를 useRef를 이용해 선언합니다.
start 버튼 클릭 여부를 판별할 isStartOperation을 false로 초기화하고,
경과된 시간을 표시하기 위한 count를 0으로 초기화하여 state에 넣어줍니다.
2) 작동 handler - start
//start 버튼 작동
const startHandler=()=>{
//start 작동 안했다면
if(!isStartOperation){
//start 작동 체크
setIsStartOperation(true);
//ref 객체에 interval 설정
timeRef.current = setInterval(()=>{
//interval에서 count 증가
setCount((x)=>x+1);
}
//100 ms 마다
,100
);
}
}
start 버튼 작동 여부를 판별하고, 작동하지 않았다면 작동 여부를 true로 변환해줍니다.
(이 작업을 하지 않는다면, start버튼을 연속으로 누를때마다 interval이 실행되어 놀라운 가속 시간을 보여줍니다(!))
timeRef.current에 100 ms 마다 count를 1씩 증가시켜줍니다.
setInterval 내에서 count를 증가시키려면 setCount((x)=>x+1) 과 같이 적어야
100 ms마다 값이 갱신됩니다.
3) 작동 handler - stop
//정지
const stopHandler=()=>{
//start 작동 false 체크
setIsStartOperation(false);
//ref 객체에 interval 정지
clearInterval(timeRef.current);
}
isStartOperation을 false로 바꾸고 clearInterval을 통해 타이머를 정지시킵니다.
4) 작동 handler - reset
//리셋
const resetHandler=()=>{
stopHandler();
setCount(0);
}
stop을 실행하고, count를 0으로 초기화시킵니다.
5) jsx
return(
<div className="stopwatch">
<div className="stopwatch_title">
스톱워치
</div>
<div className="timer">
{parseInt(count/10/60/60,10)}:{parseInt(count/10/60%60,10)}
:{parseInt(count/10%60,10)}.{parseInt(count%10,10)} 초
</div>
<div className="button_wrap">
<button onClick={startHandler}>Start</button>
<button onClick={stopHandler}>Stop</button>
<button onClick={resetHandler}>Reset</button>
</div>
</div>
)
}
시간은 시:분:초 를 표시하며, 소수점 1자리까지(100ms) 초를 표시합니다.
각 버튼을 누를떄마다 위에서 지정한 handler가 실행됩니다.
6) 전체 코드
import React, { useRef, useState } from "react";
import './StopWatch.css';
function StopWatch(){
//ref 객체
const timeRef = useRef(null);
//start 작동 여부 판별할 state
const [isStartOperation,setIsStartOperation]=useState(false);
//경과 시간 state
const [count,setCount]=useState(0);
//start 버튼 작동
const startHandler=()=>{
//start 작동 안했다면
if(!isStartOperation){
//start 작동 체크
setIsStartOperation(true);
//ref 객체에 interval 설정
timeRef.current = setInterval(()=>{
//interval에서 count 증가
setCount((x)=>x+1);
}
//100 ms 마다
,100
);
}
}
//정지
const stopHandler=()=>{
//start 작동 false 체크
setIsStartOperation(false);
//ref 객체에 interval 정지
clearInterval(timeRef.current);
}
//리셋
const resetHandler=()=>{
stopHandler();
setCount(0);
}
return(
<div className="stopwatch">
<div className="stopwatch_title">
스톱워치
</div>
<div className="timer">
{parseInt(count/10/60/60,10)}:{parseInt(count/10/60%60,10)}
:{parseInt(count/10%60,10)}.{parseInt(count%10,10)} 초
</div>
<div className="button_wrap">
<button onClick={startHandler}>Start</button>
<button onClick={stopHandler}>Stop</button>
<button onClick={resetHandler}>Reset</button>
</div>
</div>
)
}
export default StopWatch;
7) 결과
'프론트엔드 > React' 카테고리의 다른 글
리액트 배열에 데이터 추가하기 (0) | 2022.05.13 |
---|---|
리액트 배열형 자료의 랜더링 (0) | 2022.05.11 |
리액트 useRef(1) DOM 선택 (0) | 2022.05.07 |
리액트 useState 여러 요소 다루기 (0) | 2022.05.06 |
리액트 함수형 컴포넌트 (0) | 2022.05.05 |
댓글