React 18 Suspense로 데이터 페칭 개선하기

문제 상황

대시보드 페이지에서 여러 API를 동시에 호출하는데, 각 컴포넌트마다 isLoading, isError 상태를 관리하다 보니 코드가 지저분했다. 특히 중첩된 컴포넌트에서 로딩 상태를 props로 전달하는 게 번거로웠다.

function Dashboard() {
  const { data: user, isLoading: userLoading } = useUser();
  const { data: stats, isLoading: statsLoading } = useStats();
  
  if (userLoading || statsLoading) return <Spinner />;
  // ...
}

Suspense 적용

React 18부터 Suspense가 데이터 페칭에서도 안정적으로 사용 가능하다고 해서 TanStack Query v4와 함께 적용했다.

function Dashboard() {
  return (
    <Suspense fallback={<Spinner />}>
      <UserSection />
      <StatsSection />
    </Suspense>
  );
}

function UserSection() {
  const { data } = useSuspenseQuery({
    queryKey: ['user'],
    queryFn: fetchUser
  });
  return <div>{data.name}</div>;
}

결과

로딩 상태 관리 코드가 대폭 줄었고, 컴포넌트가 데이터가 있다고 가정하고 작성할 수 있어서 타입스크립트 타입 체크도 단순해졌다. Error Boundary와 조합하면 에러 처리도 선언적으로 가능하다.

다만 Suspense 경계를 어디에 둘지 고민이 필요했다. 너무 상위에 두면 일부 데이터만 로딩 중일 때도 전체가 fallback으로 대체되니, 적절한 단위로 쪼개는 게 중요했다.

아직 모든 라이브러리가 Suspense를 완전히 지원하는 건 아니지만, React 18의 방향성에 맞춰 점진적으로 적용해볼 만하다.