노트

Suspense

Suspense

프런트엔드#react · 연결된 개념 19개

쉽게 말하면

Suspense는 아직 준비 안 된 화면 구역 앞에 '준비 중' 팻말을 세워 두는 장치예요. 컴포넌트마다 로딩 상태를 따로 챙기지 않고, 가장 가까운 경계가 팻말을 보여 주다가 준비되면 치워요.

비유가 깨지는 곳 단순한 스피너 기능이 아니에요. 렌더 중 던진 Promise를 경계가 받아 주는 구조라서 스트리밍 SSR, 선택적 하이드레이션처럼 비동기 UI의 순서를 조율하는 바탕이 돼요. 실패는 Error Boundary가 맡아요.

Suspense는 아직 준비되지 않은 하위 트리의 렌더를 잠시 보류(suspend)하고, 그동안 가장 가까운 경계의 fallback을 보여 주는 React의 비동기 렌더링 메커니즘이다. 로딩 상태를 컴포넌트마다 들고 있지 않고 경계에 위임한다.

<ErrorBoundary fallback={<ErrorPage />}>
  <Suspense fallback={<Spinner />}>
    <UserProfile />        {/* 준비 전이면 Spinner, 실패하면 ErrorPage */}
  </Suspense>
</ErrorBoundary>
  • 원리: 데이터가 없으면 컴포넌트가 렌더 중에 Promise를 던진다(throw promise). React는 렌더를 멈추고 가장 가까운 경계의 fallback을 그린 뒤, Promise가 끝나면 다시 렌더한다. 직접 던지지 않고 use()나 useSuspenseQuery 같은 Suspense 지원 API(Application Programming Interface)를 통해 쓴다
  • 경계는 중첩된다. 영역마다 경계를 두면 각자 독립적으로 준비되는 대로 나타난다. 경계를 어디에 둘지가 곧 로딩 UX(User Experience) 설계다
  • 에러 경계(Error Boundary)와 역할을 나눈다. Suspense는 던져진 Promise(로딩), Error Boundary는 던져진 Error(실패)를 처리한다
  • 이미 보이는 내용이 다시 suspend될 때 fallback으로 갈아엎지 않으려면 업데이트를 transition으로 감싼다

왜 중요해졌나

React 18 이전 SSR(Server-Side Rendering)은 "모든 데이터 → 모든 HTML(HyperText Markup Language) → 모든 JS(JavaScript) → 전체 하이드레이션"이 앞 단계를 기다리는 폭포수였다. Suspense가 앱을 독립 단위로 나누면서 준비된 부분부터 HTML을 보내는 스트리밍 SSR, 경계별로 먼저 살아나는 선택적 하이드레이션, 서버 컴포넌트, 부분 사전 렌더링(PPR)이 가능해졌다. Next.js의 loading.tsx는 페이지를 Suspense로 감싸는 단축 문법이다. 그래서 Suspense는 로딩 스피너 기능이라기보다 비동기 UI의 순서를 조율하는 장치다.

출처: New Suspense SSR Architecture in React 18 · React - Suspense

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • useSyncExternalStore

    useSyncExternalStore는 React 밖에 있는 상태(외부 스토어(External Store), 브라우저 API(Application Programming Interface))를 구독해 컴포넌트와 동기화하는 훅이다. 동시성 렌더링(Concurrent Rendering)에서도 모든 컴포넌트가 같은 스냅샷을 보게 보장해 tearing을 막는다(React 18+).

보기 옵션