본문으로 바로가기

 

 

왜 useEffect의 콜백 인수로 비동기 함수를 바로 넣을 수 없을까요?

아래 코드는 첫 번째 인수에 비동기 함수를 넣으니 발생한 경고문입니다.

useEffect의 첫 번째 인수로 비동기 함수를 바로 넣을 시 나오는 경고문

 

useEffect 내부에서 state를 결과에 따라 업데이트하는 로직이 있다고 가정해 봅시다. 만약에 useEffect의 인수로 비동기 함수가 사용 가능하다면 비동기 함수의 응답 속도에 따라 결과가 이상하게 나타날 수 있습니다. 극단적인 예제로 이전 state 기반의 응답이 10초가 걸렸고, 이후 바뀐 state 기반의 응답이 1초 뒤에 왔다면 이전 state 기반으로 결과가 나와버리는 불상사가 생길 수 있습니다. 이러한 문제를 useEffect의 경쟁 상태(race condition)라고 합니다

 

그렇다면 비동기 함수는 어떻게 실행할 수 있을까요? 한 가지 유념해야 할 사실은 useEffect의 인수로 비동기 함수를 지정할 수 없는 것이지, 비동기 함수 실행 자체가 문제가 되는 것은 아니라는 사실입니다. useEffect 내부에서 비동기 함수를 선언해 실행하거나, 즉시 실행 비동기 함수를 만들어서 사용하는 것은 가능합니다.

useEffect(() => {
    let shouldIgnore = false;

    async function fetchData() {
      const response = await fetch('https://itprogramming119.tistory.com');
      const result = await response.json();
      
      if (!shouldIgnore) {
        setData(result)
      }
    }

    fetchData();

    return () => {
      // shouldIgnore를 이용해 useState의 두 번쨰 인수를 실행을 막는 것뿐만 아니라
      // 직전 요청 자체를 취소하는 것도 좋은 방법이 될 수 있음
      shouldIgnore = true;
    }
  }, [])

 

다만 비동기 함수가 내부에 존재하게 되면 useEffect 내부에서 비동기 함수가 생성되고 실행되는 것을 반복하므로 클린업 함수에서 이전 비동기 함수에 대한 처리를 추가하는 것이 좋습니다. fetch의 경우 이전 요청을 취소하는 것이 좋습니다.

 

즉, 비동기 useEffect는 state의 경쟁 상태를 야기할 수 있고 클린업 함수의 실행 순서도 보장할 수 없기 때문에 개발자의 편의를 위해 useEffect에서 비동기 함수를 인수로 받지 않는다고 볼 수 있습니다.

 

 

 

References

[React] useEffect란?

모던 리액트 Deep Dive