개요
<Suspense>
는 자식 컴포넌트가 로딩 중일 때 대체 UI(fallback)를 표시할 수 있게 해주는 React 컴포넌트입니다. 데이터 로딩, 코드 스플리팅 등 비동기 작업이 완료될 때까지 로딩 스피너 등 임시 UI를 보여줄 수 있습니다.
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
Reference
<Suspense>
Props
children
: 실제로 렌더링하고자 하는 UI. children이 렌더링 중에 suspend(로딩 대기) 상태가 되면 fallback이 대신 렌더링됩니다.fallback
: children이 로딩 중일 때 대신 보여줄 UI. 보통 로딩 스피너, 스켈레톤 등 가벼운 뷰를 사용합니다.
Caveats
- Suspense는 최초 마운트 전에 suspend된 렌더에 대해 state를 보존하지 않습니다. 데이터가 준비되면 트리를 처음부터 다시 렌더링합니다.
- 이미 보여주던 트리가 suspend되면, startTransition이나 useDeferredValue로 발생한 업데이트가 아닌 한 fallback이 다시 표시됩니다.
- 이미 보이던 콘텐츠가 숨겨질 때, React는 해당 트리의 layout Effect를 cleanup합니다. 콘텐츠가 다시 보이면 Effect가 재실행됩니다.
- Suspense는 스트리밍 서버 렌더링, 선택적 하이드레이션 등 React의 내부 최적화와 연동됩니다.
사용법
로딩 중 fallback 표시하기
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
- children이 suspend 상태가 되면 fallback이 표시되고, 데이터가 준비되면 children이 다시 렌더링됩니다.
여러 컴포넌트 동시 로딩
<Suspense fallback={<Loading />}>
<Biography />
<Panel>
<Albums />
</Panel>
</Suspense>
- 하나라도 suspend되면 전체가 fallback으로 대체되고, 모두 준비되면 한 번에 나타납니다.
중첩 Suspense로 부분별 로딩
<Suspense fallback={<Loading />}>
<Biography />
<Suspense fallback={<SmallLoading />}>
<Albums />
</Suspense>
</Suspense>
- 중첩 구조로 각 부분별로 로딩 상태를 다르게 제어할 수 있습니다.
stale content 유지하며 새 데이터 로딩
- startTransition, useDeferredValue 등과 함께 사용하면, 이미 보이던 콘텐츠를 숨기지 않고 새 데이터가 준비될 때까지 유지할 수 있습니다.
서버 렌더링/클라이언트 전용 컴포넌트 fallback 처리
<Suspense fallback={<Loading />}>
<Chat />
</Suspense>
function Chat() {
if (typeof window === 'undefined') {
throw Error('Chat should only render on the client.');
}
// ...
}
- 서버에서 에러가 발생하면 fallback이 서버 HTML에 포함되고, 클라이언트에서 준비되면 교체됩니다.
트러블슈팅
업데이트 중 fallback으로 UI가 교체되는 현상 방지
- startTransition 등으로 비긴급 업데이트로 표시하면, 이미 보이던 콘텐츠가 숨겨지지 않고 새 데이터가 준비될 때까지 유지됩니다.
function handleNextPageClick() {
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
- 새로 렌더되는 Suspense 경계는 즉시 fallback을 표시하지만, 기존에 보이던 콘텐츠는 숨기지 않습니다.
반응형