[마켓컬리 클론코딩- 타이머 구현]
정해진 기한의 값을 받아와서 현재시간과의 차이를 구해 남은 시간을 계산하는 타이머를 만들고자 한다.
현재 day.js 라이브러리를 사용하고 있어 이를 활용하였으며, 활용도를 높이기 위해서 커스텀 훅을 사용하여 만들었다.
사용
커스텀 훅을 사용하는 컴포넌트는 다음과 같다.
targetTime: 기한 날짜(언제까지인지 날짜 작성)
export default function TimeArticle() {
const targetTime = '2023-07-29 00:00:00';
const { remainingTime } = useCountDownTimer(targetTime);
return (
<div>
<p>{remainingTime}</p>
</div>
);
}
타이머 커스텀 훅
import { useEffect, useState } from 'react';
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration'; //dayjs 내 플러그인 import
dayjs.extend(duration); //이걸 해줘야 duration사용가능
//매개변수로 기한을 받아와서 현재시간과의 차이를 구해 남은시간을 계산
export default function useCountDownTimer(targetTime: string) {
const [remainingTime, setRemaingTime] = useState('');
useEffect(() => {
const calculateRemainingTime = () => {
const currentTime = dayjs(); //현재시간
const targetDate = dayjs(targetTime); //전달받는 기한 날짜
const duration = dayjs.duration(targetDate.diff(currentTime)); //diff:차이구하기/duration:차이구한것을 객체로 반환해줌
const days = String(duration.days()).padStart(2, '0'); //padStart(목표문자열길이,모자라면채워지는값)
const hours = String(duration.hours()).padStart(2, '0');
const minutes = String(duration.minutes()).padStart(2, '0');
const seconds = String(duration.seconds()).padStart(2, '0');
//setRemaingTime(`${days}일 ${hours}시간 ${minutes}분 ${seconds}초`);
setRemaingTime(`${hours}: ${minutes}: ${seconds}`);
};
const intervalId = setInterval(calculateRemainingTime, 1000); //1초마다 불러오기
return () => clearInterval(intervalId);
}, [targetTime]);
return {
remainingTime,
};
}
결과화면
1초마다 갱신되어 화면에 잘 나타난다.😀
+
다른 예제 1
만약 targetTime이 2023-07-29 00:00:00가 아닌 현재 날짜를 기준으로 +1일이 되고 00:00:00이라면?
사용 컴포넌트
dayjs 메소드를 활용한다. add를 통해 +1일을 설정, startOf를 통해 시작시간인 00:00:00을 설정한다.
export default function TimeArticle() {
const targetTime = dayjs().add(1, 'day').startOf('day');
...
커스텀 훅 변경
- 매개변수 targetTime type변경
- dayjs(targetTime)> dayjs로 객체로 만들어줬던걸 이미 위에서 했기 때문에 삭제
import dayjs, { Dayjs } from 'dayjs';
export default function useCountDownTimer(targetTime:Dayjs) {
..
useEffect(() => {
const calculateRemainingTime = () => {
...
const targetDate = targetTime; //전달받는 기한 날짜
+
다른 예제 2
현재날짜의 +1일에 오전11:00:00을 설정한 경우이다.
add로 현재날짜에 +1일을 하고, set을 통해 시간을 재설정해준다.
export default function TimeArticle() {
//현재날짜의 +1일에 오전11:00:00을 설정한 경우
const targetDay = dayjs().add(1, 'day');
const targetTime = targetDay
.set('hour', 11)
.set('minute', 0)
.set('second', 0);
const { remainingTime } = useCountDownTimer(targetTime);
커스텀훅에서의 변경은 위와 동일하다.
import dayjs, { Dayjs } from 'dayjs';
export default function useCountDownTimer(targetTime:Dayjs) {
..
useEffect(() => {
const calculateRemainingTime = () => {
...
const targetDate = targetTime; //전달받는 기한 날짜
결과화면
남은 시간이 보이는 타이머가 잘 작동된다.
+
다른예제3
예제2와 기한은 동일, 다만 타이머가 종료되면 12:00:00같은 시간대신 TIMER OUT 글자가 출력되고, setInterval이 종료되도록 한다.
import { useEffect, useState } from 'react';
import dayjs, { Dayjs } from 'dayjs';
import duration from 'dayjs/plugin/duration'; //dayjs 내 플러그인 import
dayjs.extend(duration);
//매개변수로 기한을 받아와서 현재시간과의 차이를 구해 남은시간을 계산
export default function useCountDownTimer(targetTime: Dayjs) {
const [remainingTime, setRemaingTime] = useState('');
useEffect(() => {
const calculateRemainingTime = () => {
const currentTime = dayjs(); //현재시간
// const targetDate = dayjs(targetTime); //전달받는 기한 날짜(명시적으로 작성하는 경우)
const targetDate = targetTime; //전달받는 기한 날짜
const duration = dayjs.duration(targetDate.diff(currentTime)); //diff:차이구하기/duration:차이구한것을 객체로 반환해줌
//만약 남은시간(asMilliseconds밀리초로 바꿈)이 0보다 크면 실행
if (duration.asMilliseconds() > 0) {
const days = String(duration.days()).padStart(2, '0'); //padStart(목표문자열길이,모자라면채워지는값)
const hours = String(duration.hours()).padStart(2, '0');
const minutes = String(duration.minutes()).padStart(2, '0');
const seconds = String(duration.seconds()).padStart(2, '0');
//setRemaingTime(`${days}일 ${hours}시간 ${minutes}분 ${seconds}초`);
setRemaingTime(`${hours}:${minutes}:${seconds}`);
} else {
setRemaingTime('TIME OUT'); //시간경과시
}
};
//타이머 실행때에만 setInterval되도록 적용/return되면 clearInterval되어 끝나도록 설정
if (remainingTime !== 'TIME OUT') {
const intervalId = setInterval(calculateRemainingTime, 1000); //1초마다 불러오기
return () => clearInterval(intervalId);
}
return;
}, [targetTime, remainingTime]);
return {
remainingTime,
};
}
결과화면
타이머 종료시 글자가 TIME OUT으로 변하고, 그에 따른 블라인드 모달처리도 추가 적용하였다.
dayjs 참고하기
- diff
- duration
참고사이트)
'React' 카테고리의 다른 글
[React] 팝업 띄우기(feat. Modal, 오늘 그만 보기) (0) | 2023.08.07 |
---|---|
[React] lottie-react 사용법 (lottie 애니메이션) (0) | 2023.07.31 |
[React] 정상가, 할인된 금액이 있을 경우 %퍼센트 구하기 (0) | 2023.07.28 |
[React] 쿠키 저장하기 (react-cookie/서브 도메인 달라도 쿠키 공유) (0) | 2023.07.27 |
[React] 숫자 세자리마다 , 콤마 붙이기 (0) | 2023.07.26 |