본문 바로가기
개발/React

리액트 - useRef를 이용하여 타이머 만들기

by 피로물든딸기 2022. 3. 23.
반응형

리액트 전체 링크

 

로컬 변수를 사용할 때 useRef를 활용할 수 있다.

useRef는 current 속성을 가지고 있고 이 값을 변경해도 컴포넌트가 렌더링되지 않는다.

 

Timer component에서 시간, 분, 초를 입력받는다고 가정하자.

count할 시간은 시간에 3600, 분에 60을 곱한 후 나온 결과를 초와 함께 더한다.

그리고 setInterval를 담을 interval도 useRef로 선언한다.

const Timer = ({ hh, mm, ss }) => {
  const HH = hh ? parseInt(hh) : 0;
  const MM = mm ? parseInt(mm) : 0;
  const SS = ss ? parseInt(ss) : 0;
  
  const count = useRef(HH * 60 * 60 + MM * 60 + SS);
  const interval = useRef(null);

 

각 시간에 대한 변수는 useState로 선언해둔다.

  const [hour, setHour] = useState(intToString(HH));
  const [minute, setMinute] = useState(intToString(MM));
  const [second, setSecond] = useState(intToString(SS));

 

padStart 함수를 이용하여 숫자가 10보다 작은 경우는 0을 추가로 붙이도록 한다.

const intToString = (num) => {
  return String(num).padStart(2, "0");
};

 

useEffect로 최초로 렌더링할 때 시간을 계산하여 카운트 다운이 되도록 한다.

count가 HH * 60 * 60 + MM * 60 + SS로 시작하였으므로, 

다시 hour, minute, second로 변경한다.

  useEffect(() => {
    interval.current = setInterval(() => {
      count.current -= 1;

      setHour(intToString(parseInt(count.current / 3600)));
      setMinute(intToString(parseInt((count.current % 3600) / 60)));
      setSecond(intToString((count.current % 60)));
    }, 1000);
  }, []);

 

매 초가 흐를 때마다 timer를 보여주므로, second가 변경될 때마다 count가 남아있는지 체크한다.

0이 될 경우 clearInterval로 setInterval를 종료한다.

  useEffect(() => {
    if (count.current <= 0) {
      clearInterval(interval.current);
    }
  }, [second]);

 

최종코드는 아래와 같다.

import React, { useState, useEffect, useRef } from 'react';

const intToString = (num) => {
  return String(num).padStart(2, "0");
};

const Timer = ({ hh, mm, ss }) => {
  const HH = hh ? parseInt(hh) : 0;
  const MM = mm ? parseInt(mm) : 0;
  const SS = ss ? parseInt(ss) : 0;
  
  const count = useRef(HH * 60 * 60 + MM * 60 + SS);
  const interval = useRef(null);

  const [hour, setHour] = useState(intToString(HH));
  const [minute, setMinute] = useState(intToString(MM));
  const [second, setSecond] = useState(intToString(SS));

  useEffect(() => {
    interval.current = setInterval(() => {
      count.current -= 1;

      setHour(intToString(parseInt(count.current / 3600)));
      setMinute(intToString(parseInt((count.current % 3600) / 60)));
      setSecond(intToString((count.current % 60)));
    }, 1000);
  }, []);

  useEffect(() => {
    if (count.current <= 0) {
      clearInterval(interval.current);
    }
  }, [second]);

  return (
    <div>
      {hour} : {minute} : {second}
    </div>
  );
};

export default Timer;

 

아래와 같이 component를 만들어서 사용할 수 있다.

<Timer hh="5" mm="0" ss="9"/>

반응형

댓글