written by yechoi

[React] useEffect로 경과시간 실시간 업데이트하기 본문

Born 2 Code/frontend

[React] useEffect로 경과시간 실시간 업데이트하기

yechoi 2021. 7. 5. 17:15
반응형

 

오른쪽 상단의 게임 경과 시간을 업데이트 해주기 위해 찾아본 내용

데이터 가져오기, 구독(subscription) 설정하기, 수동으로 리액트 컴포넌트의 DOM을 수정하는 것까지 이 모든 것이 side effects입니다. 이런 기능들(operations)을 side effect(혹은 effect)라 부르는 것이 익숙하지 않을 수도 있지만, 아마도 이전에 만들었던 컴포넌트에서 위의 기능들을 구현해보았을 것입니다.

useEffect가 하는 일은 무엇일까요? useEffect Hook을 이용하여 우리는 리액트에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 말합니다. 리액트는 우리가 넘긴 함수를 기억했다가(이 함수를 ‘effect’라고 부릅니다) DOM 업데이트를 수행한 이후에 불러낼 것입니다. 위의 경우에는 effect를 통해 문서 타이틀을 지정하지만, 이 외에도 데이터를 가져오거나 다른 명령형(imperative) API를 불러내는 일도 할 수 있습니다.

useEffect를 컴포넌트 안에서 불러내는 이유는 무엇일까요? useEffect를 컴포넌트 내부에 둠으로써 effect를 통해 count state 변수(또는 그 어떤 prop에도)에 접근할 수 있게 됩니다. 함수 범위 안에 존재하기 때문에 특별한 API 없이도 값을 얻을 수 있는 것입니다. Hook은 자바스크립트의 클로저를 이용하여 리액트에 한정된 API를 고안하는 것보다 자바스크립트가 이미 가지고 있는 방법을 이용하여 문제를 해결합니다.

useEffect는 렌더링 이후에 매번 수행되는 걸까요? 네, 기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행됩니다.(나중에 effect를 필요에 맞게 수정하는 방법에 대해 다룰 것입니다.) 마운팅과 업데이트라는 방식으로 생각하는 대신 effect를 렌더링 이후에 발생하는 것으로 생각하는 것이 더 쉬울 것입니다. 리액트는 effect가 수행되는 시점에 이미 DOM이 업데이트되었음을 보장합니다.

 

정리(Clean-up)를 이용하지 않는 Effects

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // count가 바뀔 때만 effect를 재실행합니다.

effect

useEffect안의 함수, 즉 아래부분이 effect입니다.

() => {
  document.title = `You clicked ${count} times`;
}

같은 함수 내부에 있기 때문에 최신의 count를 바로 얻을 수 있습니다. 컴포넌트를 렌더링할 때 리액트는 우리가 이용한 effect를 기억하였다가 DOM을 업데이트한 이후에 실행합니다. 이는 맨 첫 번째 렌더링은 물론 그 이후의 모든 렌더링에 똑같이 적용됩니다.

useEffect의 두번째 인수인 배열

위의 예시에서 우리는 [count]를 두 번째 인수로 넘깁니다. 이것이 의미하는 바는 다음과 같습니다. 만약 count5이고 컴포넌트가 리렌더링된 이후에도 여전히 count는 변함없이 5라면 리액트는 이전 렌더링 시의 값 [5]를 그다음 렌더링 때의 [5]와 비교합니다. 배열 내의 모든 값이 같기 때문에(5 === 5) 리액트는 effect를 건너뛰게 됩니다. 이런 식으로 최적화가 가능합니다.

count6으로 업데이트된 뒤에 렌더링하면 리액트는 이전에 렌더링된 값 [5]를 그다음 렌더링 시의 [6]와 비교합니다. 이때 5 !== 6 이기 때문에 리액트는 effect를 재실행합니다. 배열 내에 여러 개의 값이 있다면 그중의 단 하나만 다를지라도 리액트는 effect를 재실행합니다.

 

정리(clean-up)를 이용하는 Effects

effect에 정리(clean-up)가 필요한 경우에는 함수를 반환합니다. 아래는 Gamecard에서 게임 경기 진행 시간을 체크하는 부분입니다.

  const isoStartTime: Date = useMemo(() => new Date(startTime), [startTime]);
  const [runningTime, setRunningTime] = useState(getRunningTime(isoStartTime));

  useEffect(() => {
    const interval = setInterval(() => {
      setRunningTime(getRunningTime(isoStartTime));
    }, 1000);
    return () => {
      clearInterval(interval);
    };
  }, [isoStartTime]);

effect로 사용한 setInterval 은 일정시간마다 함수를 실행하는 메서드입니다. 첫번쨰 인자로 반복해 실행할 함수, 두번재 인자로 반복할 주기(ms단위)를 설정합니다.

setInterval는 정리가 필요한 함수입니다. 반환값에 clearInterval 함수를 반환해 정리해주겠습니다. clearIntervalsetInterval 의 반복을 멈추게 합니다.

🔗 출처: 리액트 공식 문서 

반응형