Suspense는 기다림을 잡는 경계야. 로딩 UI를 경계에 맡기면 데이터를 쓰는 컴포넌트는 성공 경로에 집중할 수 있어.
작동 원리
자식 컴포넌트가 use(somePendingPromise)로 대기 중인 프로미스를 읽으면 React는 해당 렌더링을 중단해. 트리를 거슬러 올라가 가장 가까운 Suspense 경계를 찾고 그 경계의 대체 UI를 보여 줘. 프로미스가 이행되면 중단됐던 부분을 다시 렌더링해 실제 콘텐츠로 바꿔.
경계의 크기
페이지 전체를 경계 하나로 감싸면 구현은 쉽지만 데이터 하나를 기다릴 때도 화면 전체가 spinner로 바뀌어. 사이드바와 메인 패널처럼 의미 있는 영역별로 나누면 준비된 부분은 그대로 사용할 수 있어. 반대로 목록의 모든 행을 따로 감싸면 구조와 로딩 UI가 지나치게 복잡해질 수 있으니, 사용자가 하나의 섹션으로 인식하는 범위를 기준으로 골라.
중첩된 경계
안쪽 경계는 자기 자식에서 발생한 중단을 먼저 처리하고, 안쪽에 경계가 없으면 바깥 경계가 맡아. 페이지 shell은 즉시 보여 주고 데이터 섹션만 나중에 채우는 구조를 이 중첩으로 만들 수 있어.
Transition과 함께 쓰기
검색이나 필터 변경이 새 데이터를 요구할 때 평범한 상태 업데이트를 하면 기존 화면이 곧바로 대체 UI로 바뀔 수 있어. startTransition으로 긴급하지 않은 업데이트라고 알려 주면 React가 새 화면을 준비하는 동안 기존 화면을 유지해 더 부드럽게 전환할 수 있어.
경계의 크기가 로딩 경험을 정해
앱 전체를 Suspense 하나로 감싸면 작은 위젯 하나가 기다릴 때도 화면 전체가 대체 UI로 바뀔 수 있어. Sidebar, 본문, 보조 패널처럼 서로 독립적으로 준비될 수 있는 영역에 경계를 나누면 먼저 준비된 부분부터 보여 줄 수 있어.
중첩 경계는 가장 가까운 곳이 처리해
자식이 대기 중 프로미스를 읽으면 가장 가까운 Suspense가 중단 신호를 받아. 안쪽 경계가 없으면 바깥쪽으로 올라가고, 어떤 조상에도 없으면 정상적인 로딩 UI 대신 오류가 돼.
Fallback은 최종 화면과 비슷한 크기를 유지해 layout shift를 줄여. 오류는 Suspense가 아니라 오류 경계가 처리하므로 두 경계를 필요한 순서로 함께 배치해야 해.