앱에서 THE RISE 이벤트가 진행 중입니다. 투표를 통해서 새로운 신예 래퍼를 뽑는 이벤트인데, 투표 종료시간이 정해져 있어 앱 내 투표 종료까지 남은 시간을 보여주는 타이머를 개발하였습니다⏱
타이머 개발과useInterval
에 관해 정리한 글입니다!
useInterval 은 Dan abramov 형님이 만든 커스텀 훅입니다.
Dan이 쓴 setInterval 글 읽어보기!
// useInterval.js
import { useEffect, useRef } from 'react';
const useInterval = (callback, delay) => {
const savedCallback = useRef(); // { current: null }
// 마지막으로 받아온 callback을 savedCallback에 저장합니다
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
};
export default useInterval;
인자로 들어온 callback을 useRef()
를 사용한 변수 savedCallback의 current 프로퍼티에 저장합니다.
useRef()
를 사용한 이유는 리렌더링 방지를 위해서 입니다. 함수형 프로그래밍에서 사용하는ref
로 초기화 된 ref 객체인{ current: null }
을 반환하며 반환된 객체는 컴포넌트의 생애주기 동안 유지됩니다. 그러므로useRef()
로 관리하는 current 값은 값이 변경돼도 리렌더링이 일어나지 않습니다!
그리고 두번 째 useEffect에서 setInterval 함수를 인자 delay 마다 딜레이를 줘서 savedCallback.current에 저장된 callback 함수를 실행합니다.
delay는 렌더 사이에 변화도 가능합니다!
null
을 delay에 전달하는 것으로 interval을 일시 정지할 수 있습니다.
const [delay, setDelay] = useState(1000);
const [isRunning, setIsRunning] = useState(true);
useInterval(() => {
setCount(count + 1);
}, isRunning ? delay : null);
useInterval(setVoteTimer, isRunning ? delay : null);
최종적으로 useInterval을 사용하여 코드는 한 줄로 작성이 가능해졌습니다.
/**
* 투표 남은 시간 구하는 함수
*/
const setVoteTimer = () => {
const endDt = externalEventData.voteEndDate;
if (endDt) {
const seconds = 1; // 초 (밀리초)
const minute = seconds * 60; // 분
const hour = minute * 60; // 시
const day = hour * 24; // 일
const today = new Date().getTime(); // 오늘
... 중략
const restDate = [날짜, 시간, 분, 초]; // 예시로 작성한 코드입니다.
setDateList(restDate);
}
}
};
useInterval에 넘겨준 callback 함수인 setVoteTimer는 종료날짜와 현재날짜를 비교해 배열에 [날짜, 시간, 분, 초]
를 따로 저장하여 set해주면, 화면에 1초 마다 시간이 갱신되어 타이머 형태로 나타나게 됩니다.
이벤트 자체가 마켓팅팀에서 급하게 성사되어 2~3일 사이로 개발을 끝나고 QA에 곧바로 들어가야했습니다. 시간에 쫓겼지만 커스텀 훅을 써볼 수 있는 좋은 계기가 되었습니다!