useEffect에서 data fetch 지양하기, 왜?

yeshyungseok·2024년 3월 11일
post-thumbnail

들어가며

최근에 모 기업의 과제 테스트에 대한 피드백으로 useEffect의 부적절한 사용에 대한 지적을 받았다.

구체적인 피드백은 없었지만 나의 추측 상 useEffect 내에서 데이터를 불러오는 로직을 구현해 그런 것 같다(사실 useEffect를 이곳밖에 안 쓰긴 했다).


  const updateCourses = async () => {
    const response = await getCourses(offset, COURSE_PER_PAGE, keyword, chips);
    setData(response);
  };
  
  useEffect(() => {
    router.push(getUpdatedUrlQuery(pathname, keyword, chips));
    updateCourses();
  }, [keyword, chips, offset]);

위 코드를 살펴보면 updateCourses 함수는 서버에서 데이터를 불러오는데, keyword, chips, offset 값이 변경될 때마다 새로운 데이터를 요청하게 된다.

위 사진은 다른 분의 블로그에서 발췌했다. 리액트 공식 문서에 따르면 데이터를 페치하는 경우 useEffect 사용을 지양하라고 권고한다. 그 이유는 미세한 버그가 발생할 수 있기 때문이라고 한다.

나는 이 미세한 버그가 무엇일까, 지양하는 건 알겠는데 구체적으로 왜?가 궁금했다. 그래서 그 이유를 알아보았다.

네트워크 워터폴

useEffect를 사용해 데이터를 불러오는 단점 중 하나가 네트워크 워터폴이 발생한다는 것이다. 이를 이해하기 위해서는 useEffect가 컴포넌트 생명주기를 어떻게 관리하는지에 대한 선행 지식이 있어야 한다.

리액트를 공부했다면 위와 같은 리액트 훅이 컴포넌트 생명주기를 어떻게 관리하는지에 대한 그림을 많이 봤을 것이다.

useEffect는 기본적으로 컴포넌트가 마운트 되었을 때(initial render), 업데이트 되었을 때, 언마운트 되었을 때에 대한 부수효과를 발생시킨다.

중요한 것

여기서 초점을 맞출 부분은 컴포넌트가 처음 마운트되었을 때이다. 위 그림만 살펴보아도 알 수 있는 것은 useEffect는 컴포넌트의 렌더 이후 커밋 단계에서 실행한다는 것이다.

즉, useEffect 훅을 사용하여 데이터를 불러올 때, 보통은 컴포넌트가 마운트된 후 네트워크 요청을 시작한다. 이 과정에서 문제가 발생할 수 있는데, 그것은 바로 '네트워크 워터폴' 현상이다. 만약 여러 개의 컴포넌트가 동시에 마운트되어 각각 useEffect 내에서 데이터를 불러온다면, 이러한 동시 요청들이 서로를 차단하거나 지연시킬 수 있다. 특히 서버나 네트워크가 각 요청을 순차적으로만 처리할 수 있다면, 이전 요청이 완료되기 전까지는 다음 요청이 대기해야 하기 때문에 애플리케이션의 응답성이 저하될 수 있다.

useEffect와 Promise.all

Promise.all을 사용하여 useEffect 내에서 여러 요청을 병렬로 처리할 수는 있다. 하지만 이 방식 또한 여전히 첫 렌더링 이후에 실행된다. 따라서, 초기 렌더링 이후에 추가적인 렌더링 사이클이 필요하게 되며, 이는 특히 대량의 데이터를 처리할 때 불필요한 지연을 초래할 수 있다.

왜 useEffect로 data fetch를 지양해야 하는가?

비동기적인 부작용 관리의 복잡성

useEffect 내부에서 데이터 페칭과 같은 비동기적인 작업을 수행할 때, 컴포넌트의 생명주기와 비동기 로직이 충돌하여 복잡한 상황을 초래할 수 있다. 예를 들어, 데이터를 요청한 후 컴포넌트가 언마운트되었다면, 요청이 완료되어 상태를 업데이트하려 할 때 이미 언마운트된 컴포넌트에 대한 업데이트를 시도하여 에러가 발생할 수 있다.

최적화의 어려움

useEffect를 사용한 데이터 페칭은 캐싱, 중복 요청 방지, 요청 상태 관리 등의 최적화를 수동으로 관리해야 하는 번거로움이 있다. 반면, react-query 같은 라이브러리를 사용하면 이러한 최적화가 자동으로 처리된다(서버 상태는 react-qeury를 사용하는 것을 권장한다).

가독성

데이터 페칭 로직을 useEffect와 같은 라이프사이클 훅 내부에 배치하면, 사이드 이펙트의 관리와 비즈니스 로직이 섞여 코드의 가독성이 떨어질 수 있다.

profile
FE 개발자

0개의 댓글