본문 바로가기

React

[React] 남은 시간 타이머 구현 (feat:day.js)

[마켓컬리 클론코딩- 타이머 구현]

정해진 기한의 값을 받아와서 현재시간과의 차이를 구해 남은 시간을 계산하는 타이머를 만들고자 한다.

현재 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

 

 

참고사이트)

 

Day.js · 2kB JavaScript date utility library

2kB JavaScript date utility library

day.js.org

 

[Typescript / Dayjs] 1분만에 글 작성 경과 시간 구현하기 (몇 분 전, 몇 시간 전, 며칠 전) (measure time el

유튜브 등을 보면 영상이 올라온 경과 시간등이 표시된다. 커뮤니티 등을 개발하다보면 글 작성 경과 시간을 표시해줄 필요가 있는데 Dayjs를 사용하면 간단하게 구현할 수 있다. Dayjs는 기존의

kbwplace.tistory.com