본문 바로가기
Today I learned!/오늘 하루 배운 것, 기억할 것

221119

by sweesweet 2022. 11. 19.

바닐라 자스에선 setInterval로 잘 됐었는데, 왜 리액트에서는 잘 되지않을까? 

이전에 메인 프로젝트때 setInterval을 썼었는데 그땐 잘 됐었는데, 왜 타이머처럼 시작과 종료버튼이 있을시엔 먹히지 않을까? 바닐라자스로 만든 가위바위보에서 열심히 찾아봤을때 처럼 변수로 할당한 후 똑같이 했는데 왜 되지 않을까?

 

1. 지피지기면 백전백승! 우선 setInterval과 setTImeout를 먼저 찾아봤다.

https://ko.javascript.info/settimeout-setinterval

 

setTimeout과 setInterval을 이용한 호출 스케줄링

 

ko.javascript.info

내가 그래도 많이 사용해봤으니 알고있을거라 생각했는데 이 부분은 처음 보았다.

함수와 함수의 인자들을 저렇게 받을 수있다니..!

function sayHi() {
  alert('안녕하세요.');
}

setTimeout(sayHi, 1000);
아래와 같이 함수에 인수를 넘겨줄 수도 있습니다.

function sayHi(who, phrase) {
  alert( who + ' 님, ' + phrase );
}

setTimeout(sayHi, 1000, "홍길동", "안녕하세요."); // 홍길동 님, 안녕하세요.

 

2. 인터넷에서 글 찾아보기!

분명 나같이 멸망한 사람이 있을 수도 있고, 나와 같이 헤매다가 해답을 찾은 사람이 분명히 존재할거라 생각했다. 

어떻게 하면 리액트에서 setInterval을 사용할 수 있을까 찾다가, 위와 같은 글을 알게되었다.  

https://sangcho.tistory.com/entry/ReactHooks%EC%9D%98%EB%B9%99%EC%82%B0

 

React Hooks의 커다란 빙산

* 이 글은 Iceberg of React Hooks 번역하였습니다. The Iceberg of React Hooks React Hooks, unlike Class Components, provide low-level building blocks for optimizing and composing applications with minimal boilerplate. medium.com Class Component와

sangcho.tistory.com

이 글을 읽으면서 얼마나 내가 오만했던건지 알게되었다. 난 아무것도 아는게 없을 수도 있겠다ㅋㅋㅋ

앞 부분에 프로젝트에서 setInterval을 사용했다고 했는데 그 코드는 아래와 같다. 글 속의 level-4정도의 코드인거다

기상 챌린지때 현재시간을 알려주기 위해 이렇게 사용했는데, 작동을 잘 한 것처럼 보였던건 아마도, new Date()를 할때마다 값이 변했기 때문에 멀쩡해 보였던 게 아닐까?

const MorningTime = () => {
  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());
    }, 1000);
    return () => clearInterval(id);
  }, []);
  return <div>{time.toLocaleString('ko-KR').slice(13)}</div>;
};

이번에 구현한거는 level-8정도에 해당하게 풀었다. 이전에 리액트가 아닌, 바닐라 자스에서 했듯 변수를 null에 할당하고 후에 버튼을 눌렀을 때 setInterval에 재할당 하는 방식으로 구현했었는데, 이 글에서 얘기하듯 랜더링하면 새로 함수가 실행되기 때문에 다시 null로 할당된다는 점을 간과했다.

level-9의 useRef를 사용한게 새로웠는데, 이렇게 사용할 수 있다는 점을 알고있었지만, 항상 돔요소에 접근할 때 사용했었기 때문에 많이 낯설었다. 글에서 start가 새로 호출하게 된다면, 계속 된다고 하지만 만약 다른 useState로 제어를 하게된다면 어떨까?

우선 useRef를 사용해서 제어하려  코드를 이렇게 짜봤다.

const [sec, setSec] = React.useState(0);
  const [min, setMin] = React.useState(0);
  const intervalRef = React.useRef(null);
  const getStart = () => {
    intervalRef.current = setInterval(() => {
      if (min === 0 && sec === 0) {
        // getStop();
        alert("look");
      } else if (sec === 0) {
        setMin((min) => min - 1);
        setSec((sec) => sec + 59);
      } else {
        setSec((sec) => sec - 1);
      }
      console.log(min)
    }, 1000);
  };
  const getStop = () => {
    setMin(0);
    setSec(0);
    clearInterval(intervalRef.current);
  };

이렇게 짰더니, 문제점이 발생했다. setState에 콜백 함수를 넣어서 min과 sec은 처음 실행했을 때와 같은 값이 돼서  값을 빼가는건 작동을 하지만, 00분 00초에 멈추는 것도, 00초가 될때  59초가 되거나 그러지는 못했다. 다시 고민이 많아졌다. 할일 많은데 미치겠네...ㅎㅎ 

2가지 방법을 생각했다. 

1. useState를 1개로만해서 분-초를  초로 계산후 저장 -> %60===0일때 조건 분리 후 화면에 다시 분, 초 나타내기.

2. 객체로 받아서 콜백함수를 짠다.

2번이 나을 것 같아서 2번으로 작성했다. 그랬더니 된다!!!

  const [time, setTime] = React.useState({ min: 0, sec: 0 });
  const intervalRef = React.useRef(null);
  const getStart = () => {
    intervalRef.current = setInterval(() => {
      setTime((time) => {
        let { min, sec } = time;
        if (min === 0 && sec === 0) {
          getStop();
          return { min: 0, sec: 0 };
        } else if (sec === 0) {
          return { min: min - 1, sec: 59 };
        } else {
          return { ...time, sec: sec - 1 };
        }
      });
    }, 1000);
  };
  const getStop = () => {
    clearInterval(intervalRef.current);
    setTime({ min: 0, sec: 0 });
  };

다만 지금 일시정지/ 다시 시작을 못하구있다.. 어떻게 짜야 괜찮으려나!!!

내일은 useCallback을 사용한걸 올려볼거다!!!

'Today I learned! > 오늘 하루 배운 것, 기억할 것' 카테고리의 다른 글

spa 배포시 주소창에 pathname을 직접 입력했을 때 404 에러  (0) 2022.12.13
221120  (0) 2022.11.20
220918  (0) 2022.09.18
220912  (0) 2022.09.12
[js/css/styled-component] 220704  (0) 2022.07.04