본문 바로가기

Client/React.js

<리액트 기초> setTimeout 사용하기

 

* setTimeout

 - 이번 장에서는 리액트에서 setTimeout을 사용하는 방법에 대해서 다뤄보자.

 

    timeout;
    statTime;
    endTime;

    onClickScreen = () => {
        const { state } = this.state;
        if (state==='waiting') {
            this.setState({
                state: 'ready',                
            });
            this.timeout = setTimeout( () => {
                this.setState( {
                    state: 'now',
                });
                this.startTime = new Date();
            }, Math.floor(Math.random() * 1000) + 2000); // 2초~3초 랜덤
        } else if (state === 'ready') {
            clearTimeout(this.timeout);
            this.setState( {
                state: 'waiting',
            })

        } else if (state === 'now') { 
            this.endTime = new Date();
            
        }
    };

 

 - 위는 클래스 컴포넌트 일부이다. onClick에 넣기 위한 함수인데 클릭할 때의 상태에 따라서 state라는 값을 변화 시킨다.

 

 - state가 waiting상태일 때에 클릭하면 ready로 넘어가고 setTimeout으로 2~3초 후에 state를 now로 변화하게 하였다.

 

 - 이 때를 살펴보면 위에서 별도로 timeout이라는 변수를 선언하고 여기에 setTimeout을 넣어 주었음을 알 수 있다. 이렇게 한 이유는 후에 clearTimeout으로 함수를 초기화 하기 위함이다.

 

 - else if문을 보면 'ready'상태일 때 클릭하면 state를 waiting으로 변경하도록 하는데 만약 클리어타임아웃이 없다면 위에서의 함수는 시간이 경과함에 따라 실행된다. 따라서 함수가 실행되지 않도록 clearTimeout을 해줘야하고 여기에 미리 선언한 변수가 들어간다.

 

 - 시간을 기록하기 위해서 new Date() 를 사용했다. 이 때에도 시작시간과 끝나는 시간을 별도의 변수로 선언했다. 이렇게 한 이유는 state로 넣으면 랜더링이 계속되기 때문이다.

 

* hooks에서 사용하기

 - ref를 기존에는 dom에 직접 접근할 때 사용했었지만 hooks에서는 this의 속성들을 ref로 표현할 수 있다.

 

 - 위의 코드를 hooks로 바꾸면 다음과 같다.

 

const TimeCheck = () => {
    const [ state, setState ] =useSate('waiting');
    const timeout = useRef(null);
    const startTime = useRef();
    const endTime = useRef();

    onClickScreen = () => {
        if (state==='waiting') {        	          
            timeout.current = setTimeout( () => {
                setState('now');
                startTime.current = new Date();
            }, Math.floor(Math.random() * 1000) + 2000); // 2초~3초 랜덤
            setState('ready');  
        } else if (state === 'ready') {
            clearTimeout(timeout.current);
            setState('waiting');

        } else if (state === 'now') { 
            endTime.current = new Date();
            
        }
    };

 

 - 기존에 변수로 선언했던 것들을 useRef()를 넣어서 선언하였다. useRef 이기 때문에 값을 사용할 때에는 .current를 붙여줘야 한다. useRef의 인자는 초깃값이므로 null을 쓰든 빈값이든 무관하다.

 

 - state와 Ref의 차이는 state는 리턴 부분이 다시 랜더링 된다는 점이다. useRef는 리턴 부분이 다시 실행되지 않는다. 따라서 값이 바뀌더라도 화면에 랜더링이 필요없다면 useRef를 사용하자. 참고로 useRef는 단순히 값을 기억하는 용도이므로 setState와 같이 화면이 바뀌는 것이 실행되어야 화면에 반영된다. 위의 setTimeout도 아래의 setState('ready')가 있음으로인해서 화면에 반영된다

 

 

* 배열에서의 사용

 - 임의의 배열을 만들어서 비슷한 형식의 setTimeout을 줄 수도 있다. 예를 들어서 1초간격으로 저장된 숫자들을 하나씩 보여준다고 하자.

 

    for (let i = 0; i < Numbers.length - 1; i++) {
        this.timeouts[i] = setTimeout(() => {
          this.setState((prevState) => {
            return {
              numberStates: [...prevState.numberStates, Numbers[i]],
            };
          });
        }, (i + 1) * 1000);
      }

 

 - 위와 같은 내용이 함수에 들어가게 될 것이다. 잠시 보자면 Numbers에 저장된 숫자들을 numberStates라는 배열에 1초마다 넣어가는 식이다.

 

 - timeouts 는 미리 'timeouts = []' 와 같이 선언 되어 있을 것이다. 인덱스가 0이면 1000ms 1이면 2000ms 의 시간을 가지며 배열에 저장되어있을 것이다.

 

 - 이러한 setTime은 어떻게 클리어 시킬까

 

      this.timeouts.forEach( (v) => {
        clearTimeout(v);
      });

 

 - 위와 같이 forEach를 사용하면 전부 시간을 초기화 시킬 수 있다. 이는 뒤에서 다룰 componentWillUnmount에서도 잘 쓰이게 된다.

 

 

 


 

 

참고

 

 

이 글은 ZeroCho 님의 리액트 무료 강좌를 수강하며 개인적으로 정리하며 쓰는 글입니다.

 

 

 

 

인프런

 

웹 게임을 만들며 배우는 React - 인프런

웹게임을 통해 리액트를 배워봅니다. Class, Hooks를 모두 익히며, Context API와 React Router, 웹팩, 바벨까지 추가로 배웁니다. 초급 웹 개발 프레임워크 및 라이브러리 React 웹 개발 게임개발 온라인 강

www.inflearn.com

 

유튜브

 

리액트 무료 강좌(웹게임)

 

www.youtube.com