timer 적용(버튼 누를 때 다시 돌아오기)

개발공부·2022년 12월 6일
0
post-thumbnail

* 결과(수정본)

* 만들려는 것

  • 시간에 따라 녹색바가 점점 줄어들게 하는 것을 원함
  • 시간은 12초(tailwindcss w-11/12 -> w-0/12까지 순차적으로 진행
  • (수정)답안 버튼을 누르면 12초에서 다시 처음으로 되돌아감
  • (수정) 0초가 되면 녹색바가 없어지게 적용(tailwindcss는 삼항 연산자가 적용 안 되므로, 각 조건에 맞는 값을 넣음)

* 참고

https://ko.javascript.info/settimeout-setinterval
https://ko.reactjs.org/docs/hooks-effect.html
https://handhand.tistory.com/32

* 타이머 설정

  • setInverval 함수를 이용

* setIntverval

  • 일정 시간 간격을 두고 함수를 실행함
  • setTimeout은 함수를 단 한번만 실행하나, setInterval은 함수를 주기적으로 실행
  • 함수 호출을 중단하려면 clearInterval(timerId) 필요
// 2초 간격으로 메시지를 보여줌
let timerId = setInterval(() => alert('째깍'), 2000);

// 5초 후에 정지
setTimeout(() => { clearInterval(timerId); alert('정지'); }, 5000);

* useEffect

  • useEffect hook은 componentDidMount와 componentDidUpdate, componentWillUnmount가 합쳐진 것으로 생각해도 됨
  • 타이머가 DOM에 첫 렌더링 이후 설정되고 언마운트 시 해제하기 위함
  • 컴포넌트가 렌더링 이후에 어떤 일을 수행해야 하는 지 말함
  • 컴포넌트 내부에 useEffect를 둠으로써 effect를 통해 변수, 어떤 prop도 접근 가능
  • 렌더링 이후에 매번 수행되므로 필요에 맞게 수정 필요
  • 특정 값이 리렌더링 시 변경되지 않는다면 React로 하여금 effect 건너 뛰도록 함
    -> useEffect의 선택적 인수인 두 번째 인수로 배열 넘김
    -> 두 번째 인자가 빈 배열일 경우 의존성이 존재하는 요소가 없기 때문에 화면에 한 번 렌더링 된 후 다시 호출되지 않음(componentDidMount의 역할)

* 주의할 점

  • 반환 값으로 함수를 지정해 컴포넌트가 마운트 해제되는 시점에 타이머를 해제

* useRef

  • 값이 변화하더라도 리렌더링 발생시키지 않음
  • 초기화된 변경가능한 ref 객체를 반환함(반환한 객체는 컴포넌트의 전 생애주기를 통해 유지)

* 코드

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

const GameForm = () => {
  const [sec, setSec] = useState(12);
  const time = useRef(12);
  const timerId = useRef(null);
   const [score, setScore] = useState(0);
  const [answers, setAnswers] = useState([false, false, false, false]);

  //타이머
  useEffect(() => {
    timerId.current = setInterval(() => {
      setSec(parseInt(time.current));
      time.current -= 1;
    }, 1000);

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

  //타임아웃
  useEffect(() => {
    if (time.current < 0) {
      console.log("타임 아웃");
      clearInterval(timerId.current);
    }
  }, [sec]);
  
  //답안부분
  const onClickAnswer = (e) => {
    let copy = [...answers];

    setNum(parseInt(number.current));
    number.current = number.current + 1;
    const chooseAnswer = parseInt(e.currentTarget.value);
    setShowScore(false);

    // console.log("chooseAnswer", chooseAnswer);
    // console.log("gameLists[num].answer", gameLists[num].answer);
    if (chooseAnswer === gameLists[num].answer) {
      setShowScore(true);
      setScore((score += 10));
      console.log("정답!");

      copy[0] = false;
      copy[1] = false;
      copy[2] = false;
      copy[3] = false;

      if (chooseAnswer === 1) {
        copy[0] = true;
        setAnswers(copy);
      } else if (chooseAnswer === 2) {
        copy[1] = true;
        setAnswers(copy);
      } else if (chooseAnswer === 3) {
        copy[2] = true;
        setAnswers(copy);
      } else if (chooseAnswer === 4) {
        copy[3] = true;
        setAnswers(copy);
      }
    } else {
      console.log("오답!");
    }
	
    //timer를 처음 값으로 되돌림
    time.current = 12;
    setSec(parseInt(time.current));

    console.log("copy", copy);
    console.log("answers", answers);
    console.log("score", score);

  };


  return (
        {/* time start */}
        <div className="bg-white shadow-lg p-1 rounded-full w-full h-5 mt-4">
        //해당 부분 수정
          <div
              className={`bg-light-green rounded-full h-full
              ${sec === 11 && "w-11/12"}
              ${sec === 10 && "w-10/12"}
              ${sec === 9 && "w-9/12"}
              ${sec === 8 && "w-8/12"}
              ${sec === 7 && "w-7/12"}
              ${sec === 6 && "w-6/12"}
              ${sec === 5 && "w-5/12"}
              ${sec === 4 && "w-4/12"}
              ${sec === 3 && "w-3/12"}
              ${sec === 2 && "w-2/12"}
              ${sec === 1 && "w-1/12"}
              ${sec === 0 && "w-0"}`}
            ></div>
          시간: {sec}
        </div>
        {/* time end */}
        
         {/* 버튼 부분 start */} 
         //각각 value값과 gameLists[num].answer를 비교
          <button
                  value="1" //1, 2, 3, 4
                  onClick={onClickAnswer}
                  className={`w-full bg-light-beige p-2 rounded-lg mb-3 relative`}
                >
                  <div className="rounded-lg font-bold flex ">
                    <div className="bg-white p-3 rounded-lg">1</div>
                    <div
                      id="point"
                      className="flex items-center pl-10 w-full text-lg"
                      value={gameLists[`${num}`]?.answer}
                    >
                      {gameLists[`${num}`]?.choices[0]} 
						
                       //answers[0], answers[1], answers[2], answers[3]
                      {answers[0] ? (
                        <div className="bg-light-orange pt-2 pl-1 transform rotate-45 rounded-full h-12 w-12 text-white font-bold absolute right-0 bottom-8 shadow-md">
                          <p className="transform -rotate-45 text-black text-lg">
                            +10
                          </p>
                        </div>
                      ) : null}
                    </div>
                  </div>
                </button>

         
         {/* 버튼 부분 end */}
        
  );
};

export default GameForm;
profile
개발 블로그, 티스토리(https://ba-gotocode131.tistory.com/)로 갈아탐

0개의 댓글