λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ‘¨‍πŸ’» web.dev/fe

React μ»΄ν¬λ„ŒνŠΈμ—μ„œ 타이머 μ„€μ •ν•˜κΈ° (with Hooks)

by HandHand 2021. 3. 2.

 

πŸ“Œ λ“€μ–΄κ°€λ©°

μ΄λ²ˆμ— κ΅¬ν˜„ν•  κΈ°λŠ₯

 

React λ₯Ό ν™œμš©ν•΄μ„œ 였λͺ© κ²Œμž„μ„ κ΅¬ν˜„ν•˜λ˜ 쀑에 μœ„μ™€ 같이 ν™”λ©΄ μ™Όμͺ½ 상단에 타이머λ₯Ό μ„€μ •ν•΄μ£Όκ³  μ‹Άμ—ˆμŠ΅λ‹ˆλ‹€.

μ‚¬μš©μžκ°€ λ°”λ‘‘λŒμ„ λ†“μœΌλ©΄ 타이머가 μž¬μ„€μ •λ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— Timer μ»΄ν¬λ„ŒνŠΈλ₯Ό state 에 따라
useEffect λ₯Ό ν™œμš©ν•˜μ—¬ λ‹€μ‹œ μ„€μ •ν•΄μ£ΌλŠ” 방법을 μ‚¬μš©ν•˜κΈ°λ‘œ ν–ˆμŠ΅λ‹ˆλ‹€.

 

ν˜„μž¬ hooks 을 μ΄μš©ν•΄μ„œ μ»΄ν¬λ„ŒνŠΈλ₯Ό μž‘μ„±ν•˜κ³  μžˆμ—ˆκΈ° λ•Œλ¬Έμ— 이번 ν¬μŠ€νŒ…μ—μ„œλŠ” 타이머 λ¦¬λžœλ”λ§ λ‘œμ§μ€ μ œμ™Έν•˜κ³ 
React Hooks 을 ν™œμš©ν•˜μ—¬ κ°„λ‹¨ν•œ 타이머λ₯Ό μ„€μ •ν•˜λŠ” 방법을 μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

πŸ“Œ μžλ°”μŠ€ν¬λ¦½νŠΈ 타이머 μ„€μ • ν•¨μˆ˜

μžλ°”μŠ€ν¬λ¦½νŠΈμ—λŠ” 타이머λ₯Ό μ„€μ •ν•  수 μžˆλŠ” ν•¨μˆ˜κ°€ 두 가지 μ‘΄μž¬ν•©λ‹ˆλ‹€.
ν•˜λ‚˜λŠ” setTimeout 이고 λ‚˜λ¨Έμ§€ ν•˜λ‚˜λŠ” setInterval 둜 두 ν•¨μˆ˜λŠ” λͺ©μ μ— 맞게 μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

이번 ν¬μŠ€νŒ…μ—μ„œ μ‚¬μš©ν•  setInterval ν•¨μˆ˜λŠ” 인자둜 μ‹€ν–‰μ‹œν‚¬ ν•¨μˆ˜ F 와 λŒ€κΈ° μ‹œκ°„ T λ₯Ό λ°›μ•„ 호좜 μŠ€μΌ€μ€„λ§μ„ ν•©λ‹ˆλ‹€.

let timerId = setInterval(() => {
  console.log("2μ΄ˆλ§ˆλ‹€ μ‹€ν–‰");
}, 2000);

setTimeout(() => {
  clearInterval(timerId);
}, 7000);

 

πŸ“Œ useEffect λ₯Ό ν™œμš©ν•œ 타이머 μ„€μ •

useEffect λŠ” React Hook 으둜 μ»΄ν¬λ„ŒνŠΈλ₯Ό 섀계할 λ•Œ 라이프 사이클 쀑 componentDidMount 와 componentDidUpdate 그리고 componentWillUnmount λ₯Ό μ•„μš°λ₯΄λŠ” 역할을 λ‹΄λ‹Ήν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” 타이머가 DOM에 첫 λžœλ”λ§ 이후 μ„€μ •λ˜κ³  μ–Έλ§ˆμš΄νŠΈ μ‹œ ν•΄μ œν•˜κΈ° μœ„ν•΄ useEffect λ₯Ό ν™œμš©ν•©λ‹ˆλ‹€.

 

import React, { useEffect } from "react";

const App = () => {
  useEffect(() => {
    const timerId = setTimeout(() => {
      // do something ...
    }, 1000);
    return () => clearTimeout(timerId);
  }, []);

  return <div>타이머 예제</div>;
};

export default App;

μœ„μ™€ 같이 useEffect 의 λ‘λ²ˆμ§Έ 인자λ₯Ό 빈 λ°°μ—΄λ‘œ μ„€μ •ν•  경우 μ˜μ‘΄μ„±μ΄ μ‘΄μž¬ν•˜λŠ” μš”μ†Œκ°€ μ—†κΈ° λ•Œλ¬Έμ—
화면에 ν•œλ²ˆ λžœλ”λ§ 된 이후 λ‹€μ‹œ ν˜ΈμΆœλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 

ν•œ 가지 μ£Όμ˜ν•  점은 λ°˜ν™˜ κ°’μœΌλ‘œ ν•¨μˆ˜λ₯Ό 지정해 μ»΄ν¬λ„ŒνŠΈκ°€ 마운트 ν•΄μ œλ˜λŠ” μ‹œμ μ— 타이머λ₯Ό ν•΄μ œν•΄μ£Όλ„λ‘ ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
μ΄λ ‡κ²Œ 해주지 μ•ŠμœΌλ©΄ νƒ€μ΄λ¨ΈλŠ” λΉ„λ™κΈ°λ‘œ μ§„ν–‰λ˜κΈ° λ•Œλ¬Έμ— μ»΄ν¬λ„ŒνŠΈκ°€ 마운트 ν•΄μ œλ˜λ”λΌλ„ νƒ€μ΄λ¨ΈλŠ” 없어지지 μ•ŠλŠ” 상황이 λ°œμƒν•©λ‹ˆλ‹€.

 

πŸ“Œ ν”„λ‘œμ νŠΈμ— μ μš©ν•΄λ³΄μž!

이제 이λ₯Ό ν™œμš©ν•΄μ„œ μ‹€μ œ ν”„λ‘œμ νŠΈμ— 3λΆ„μ˜ 타이머λ₯Ό κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

초 λ‹¨μœ„λ‘œ μ‹œκ°„κ°’μ„ κ³„μ‚°ν•΄μ„œ 화면에 λžœλ”λ§ν•΄μ€λ‹ˆλ‹€.
초기 λžœλ”λ§ μ‹œ 타이머λ₯Ό μ„€μ •ν•œ λ’€, λ§Œλ£Œκ°€ 될 경우 이벀트λ₯Ό λ°œμƒμ‹œν‚€λ„λ‘ μ„€κ³„ν•˜μ˜€μŠ΅λ‹ˆλ‹€.
μ΄λ•Œ ν•΄λ‹Ή μ»΄ν¬λ„ŒνŠΈκ°€ λ‹€μ‹œ λžœλ”λ§ λ˜λŠ” κ²½μš°λ‚˜ νƒ€μž„μ•„μ›ƒλ˜λŠ” 경우 타이머λ₯Ό ν•΄μ œν•΄μ£ΌκΈ° μœ„ν•΄ 각각 clearInterval 을 ν•΄μ€λ‹ˆλ‹€.

μ—¬κΈ°μ„œ λˆˆμ—¬κ²¨λ³Ό 점은 useEffect 의 dependencies 에 time λŒ€μ‹  sec 으둜 지정해쀀 κ²ƒμž…λ‹ˆλ‹€.
μ΄λŠ” useRef λŠ” 값이 λ³€ν™”ν•˜λ”λΌλ„ λ¦¬λžœλ”λ§μ„ λ°œμƒμ‹œν‚€μ§€ μ•ŠκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

const Timer = () => {
  const [min, setMin] = useState(3);
  const [sec, setSec] = useState(0);
  const time = useRef(180);
  const timerId = useRef(null);

  useEffect(() => {
    timerId.current = setInterval(() => {
      setMin(parseInt(time.current / 60));
      setSec(time.current % 60);
      time.current -= 1;
    }, 1000);

    return () => clearInterval(timerId.current);
  }, []);

  useEffect(() => {
    // λ§Œμ•½ νƒ€μž„ 아웃이 λ°œμƒν–ˆμ„ 경우
    if (time.current <= 0) {
      console.log("νƒ€μž„ 아웃");
      clearInterval(timerId.current);
      // dispatch event
    }
  }, [sec]);

  return (
    <div className="timer">
      {min} λΆ„ {sec} 초
    </div>
  );
};

 

πŸ“Œ μ°Έκ³  자료

λ°˜μ‘ν˜•

πŸ’¬ λŒ“κΈ€