(수근수근)

useEffect callback함수 async키워드를 쓰면 안되는 이유 본문

web/React

useEffect callback함수 async키워드를 쓰면 안되는 이유

InformationFarm 2023. 10. 8. 15:14

Async Effect Gotcha

gotcha : 프로그래밍에서 문제는 문서화된 대로 작동하지만 호출하기 쉽고 결과가 예상치 못하거나 불합리하기 때문에 직관에 반하고 실수를 거의 유발하는 시스템, 프로그램 또는 프로그래밍 언어의 유효한 구성입니다.

 

모두 알다시피, await키워드를 사용할 때, async함수 내부여야만 사용할 수 있다.

리액트를 개발하면, useEffect내부에서 비동기 함수를 사용해야하는 일이 꽤나 빈번하다. 특히 컴포넌트가 mount될 때, api를 불러오고 싶은경우가 많을 것이다.(react query, swr을 처음부터 쓰면, 알아서 해줍니다..)

 

예를 들어보자,

React.useEffect(async () => {
    const response = await fetch(ENDPOINT);
    const json = await response.json();

    setTemperature(json.temperature);
  }, []);

해당과 같이 useEffect를 쓰면 다음과 같은 console waring을 받을 수 있다.

It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, write the async function inside your effect and call it immediately.

이유는 다음과 같다. effect의 callback으로 비동기 함수를 사용할 수 없기 때문이다.

해결방법은 다음과 같습니다.

React.useEffect(() => {
  async function runEffect() {
    // ... Effect logic here
  }

  runEffect();

  return () => {
    //  ... Cleanup logic here
  }
}, []);

비동기 함수명을 지을 때 구처젝인 함수의 기능보다 runEffect같은 일반적인 함수명을 할 것은 권합니다.

cleanup함수에 runEffect의 function은 들어가서 안됩니다.(스코프내의 함수임)

그럼 우리는 해결방법은 알게되었습니다.

 

근데 왜! 비동기함수는 Effect의 콜백함수로 허용이 안될까요?

 

다시 해결방법을 살펴봐보시면, 왜 비동기 함수로 만들고 호출하고 바로 없애는게 바보같아보입니다.

근데 왜 그렇게 해야할까요?

가장 먼저 분명히 할 것은, 비동기함수는 promise를 반환한다는 것입니다.

for example :

async function quickExample() {
  return 5;
}

const result = quickExample();
console.log(result); // Promise

useEffect에서 반환하기로 우리가 약속한 것은 cleanup함수입니다.

다음 상황을 Effec상황을 봐봅시다.

React.useEffect(() => {
  // Effect logic: start an interval
  const intervalId = window.setInterval(() => {}, 1000);

  // Cleanup logic: stop the interval:
  return () => {
    window.clearInterval(intervalId);
  };
}, []);

우리가 useEffect를 사용할 때, 우리는 cleanup함수를 전달합니다.

리액트는 dependencies가 변경될 때마다 cleanup함수를 호출합니다.

여기서 중간에 비동기함수가 들어가야한다고 가정해봅시다.

React.useEffect(async () => {
  const intervalId = window.setInterval(() => {}, 1000);

  await someLongRunningProcess();

  // Even though we're returning a function, it'll actually
  // return a *promise* that resolves to a function:
  return () => {
    window.clearInterval(intervalId);
  };
});

비동기 함수이니 반환값이 promise가 될 것입니다.

 

만약 비동기 함수가 작업이 오래 걸리고 있을 때 unmount가 된다면 cleanup함수는 수행되지 않을겁니다.

이런한 어려운 상활을 피하기 위해서 리액트팀은 비동기함수 콜백이 불가능 하도록 결정했을 것입니다.

대신 우리는 비동기함수 로직을 감싸서 사용할 수 있습니다. 해당과 같은 경우는 cleanup함수를 즉시반환이 가능하기 때문에, 잘못된 gotcha를 피할 수 있습니다.

 

해당 글은 josh강의를 이해하기 위해 일부 정리한것입니다. 

'web > React' 카테고리의 다른 글

react memoization 2 ) React.memo  (1) 2023.10.09
react memoization 1 ) 왜 최적화 툴이 필요한가?  (0) 2023.10.09
datepicker 자동 masking하기  (0) 2023.01.05
리액트 내장 Hooks  (0) 2021.08.03
[react] socket.io 로 채팅 만들기  (3) 2021.01.20
Comments