관리 메뉴

즐겁게, 코드

useEffect 내에서 async 함수를 사용할 때의 주의점 본문

🎨 프론트엔드/React.js

useEffect 내에서 async 함수를 사용할 때의 주의점

Chamming2 2021. 4. 27. 13:50

웹 어플리케이션 특성상 로드와 동시에 서버로부터 데이터를 불러와야 하는 경우가 자주 있습니다.

아마 대부분의 경우 useEffect 또는 useLayoutEffect 훅을 활용해 렌더링이 끝난 후 데이터를 불러올 텐데요, 한번 샘플 코드를 보겠습니다.

const getGroupList = async () => {
  await axios
    .get(`${GROUP_ENDPOINT}?func=getAllGroup`)
    .then((res) => setGroupList(res.data));
};

useEffect(getGroupList, []);

컴포넌트 렌더링을 마친 후 useEffect 훅으로 getGroupList 함수를 호출해 그룹 리스트 상태값을 초기화해주고 있습니다.

그런데 이렇게 짜면 절대로 안됩니다!!

⏱ async와 useEffect

잠깐 async 함수와 useEffect의 구조를 간단히 살펴보도록 하겠습니다.

여러 프라미스를 동기적으로 다룰 수 있게 해주는 async 함수는 명시하지 않더라도 항상 프라미스를 반환합니다.

// 이렇게 속이 완전히 빈 async 함수더라도
const getData = async () => {};

console.log(getData());
// Promise { undefined } 를 출력합니다.

useEffect는 이렇게 생겼습니다.

useEffect(
  // 이펙트 함수
  () => {
  
  // 클린업 동작
  return () => {
    
  }
}, [의존값 목록])

내부의 이펙트 함수는 컴포넌트의 첫 렌더링 시와 의존값 목록의 값이 변할때 호출되며, 이펙트 함수에서 반환하는 함수는 이펙트 함수가 호출되기 전과 컴포넌트가 언마운트될때 한 번씩 호출됩니다.

 

자, 그럼 위에서 봤던 코드를 해석해보겠습니다.

// 1. getGroupList를 이펙트로 전달
useEffect(getGroupList, []);

// 2. 이펙트 함수의 본문
useEffect(() => {
  axios.get(`${GROUP_ENDPOINT}?func=getAllGroup`)
    .then((res) => setGroupList(res.data));
    
  // async 함수 특성상 항상 프라미스를 반환함.
  return new Promise();
}, []);

async 함수를 useEffect에 그대로 전달하면 구조상 프라미스를 반환할 수밖에 없고, 이펙트 함수에서는 클린업 함수를 리턴해야 하는데 리액트가 받아든건 덜렁 프라미스 하나입니다.

 

이로 인해 렌더링 성능에도 영향을 미칠 수 있고, 경우에 따라서는 다른 컴포넌트를 렌더링할 시 아예 오류를 출력하기도 합니다.

🛠 해결책

사실 개발자 도구의 경고를 잘 읽어보면 해결 방법이 깔끔하게 적혀있습니다.

const getGroupList = async () => {
  await axios
    .get(`${GROUP_ENDPOINT}?func=getAllGroup`)
    .then((res) => setGroupList(res.data));
};

useEffect(() => {
  getGroupList();
}, []);

바로 이렇게 이펙트를 익명 함수로 선언하고 함수 본문에서 async 함수를 호출하는 것인데요, 이러면 async 함수가 프라미스를 반환하더라도 이펙트는 아무것도 반환하지 않아 클린업으로 이상한 값을 넘길 우려가 사라집니다! 😄

반응형
Comments
소소한 팁 : 광고를 눌러주시면, 제가 뮤지컬을 마음껏 보러다닐 수 있어요!
와!! 바로 눌러야겠네요! 😆