클로저(closure)로 스톱워치 제작하기

조민혜·2022년 11월 14일
0

React.js

목록 보기
9/12

클로저 정의 문서(클릭)

< 카운트 다운 소스 >

import React, { Fragment, useState, useEffect, useRef } from "react";

function Solution() {
  // 분, 초 카운트 제어용
  const [inputM, setInputM] = useState(0);
  const [inputS, setInputS] = useState(0);
  const [m, setM] = useState("00");
  const [s, setS] = useState("00");

  // 타이머 고유ID 저장
  const countTimerRef = useRef();
  // 이전 클로저 함수 저장
  const oldTimerRef = useRef();

  // 일시정지 관리
  const [pauseFlag, setPauseFlag] = useState(false);

  // 메인 카운트다운
  const counter = () => {
    const countData = { minute: null, second: null };

    return (minute, second) => {
      countData.minute = countData.minute === null ? minute : countData.minute;
      countData.second = countData.second === null ? second : countData.second;

      countTimerRef.current = setInterval(function () {
        if (countData.minute === 0 && countData.second === 0) {
          clearInterval(countTimerRef.current);
          return;
        }

        const minute = countData.minute > 0 && countData.second === 0
            ? countData.minute - 1
            : countData.minute;
        const second = countData.second === 0 ? 59 : countData.second - 1;

        countData.minute = minute;
        countData.second = second;

        setM(minute < 10 ? "0" + minute : minute);
        setS(second < 10 ? "0" + second : second);
      }, 1000);
    };
  };

  // START 버튼 클릭
  const startClick = () => {
    // 분, 초 값 정리
    const minutes = Number(inputM) + parseInt(Number(inputS) / 60);
    const seconds = Number(inputS) % 60;
    setM(minutes < 10 ? "0" + minutes : minutes);
    setS(seconds < 10 ? "0" + seconds : seconds);

    // 비동기 useState 때문에 closure 함수로 사용
    const start = counter();
    oldTimerRef.current = start;
    start(minutes, seconds);
  };

  // PAUSE / RESUME 버튼 클릭
  const pAndRClick = () => {
    setPauseFlag(!pauseFlag);
  };

  // 일시정지 처리용
  useEffect(() => {
    if (pauseFlag) clearInterval(countTimerRef.current);
    else if (oldTimerRef.current) {
      oldTimerRef.current();
    }
  }, [pauseFlag]);

  // RESET 버튼 클릭
  const resetClick = () => {
    clearInterval(countTimerRef.current);

    setInputM(0);
    setInputS(0);
    setM("00");
    setS("00");
  };

  return (
    <Fragment>
      <label>
        <input
          type="number"
          onChange={(e) => setInputM(e.target.value)}
          value={inputM}
        />
        Minutes
      </label>
      <label>
        <input
          type="number"
          onChange={(e) => setInputS(e.target.value)}
          value={inputS}
        />
        Seconds
      </label>
      <button onClick={startClick}>START</button>
      <button onClick={pAndRClick}>PAUSE / RESUME</button>
      <button onClick={resetClick}>RESET</button>
      <h1 data-testid="running-clock">
        {m}:{s}
      </h1>
    </Fragment>
  );
}

export default Solution;
profile
Currently diving deeper into React.js development.

0개의 댓글