Files

63 lines
8.1 KiB
Markdown

# [[React Suspense]]
## 📌 Brief Summary
React Suspense는 비동기 작업(데이터 페칭, 컴포넌트 지연 로딩 등)이 완료될 때까지 대기하며 사용자에게 로딩 스피너와 같은 대체(Fallback) UI를 보여줄 수 있도록 하는 선언적 설계 패턴이다 [1, 2]. 특히 React Server Components(RSC) 및 Streaming SSR과 결합하여, 전체 데이터를 기다리지 않고 HTML 셸(Shell)을 즉시 렌더링한 뒤 완료되는 경계별로 데이터를 점진적으로 스트리밍하는 핵심적인 역할을 수행한다 [3, 4].
## 📖 Core Content
* **아웃 오브 오더(Out-of-order) 스트리밍 및 점진적 하이드레이션:** Suspense는 Next.js 등에서 RSC와 결합할 때 페이지 렌더링 방식을 혁신한다 [1, 5]. Suspense 경계 위에 있는 모든 요소는 즉시 렌더링되어 클라이언트로 전송되며, 경계 아래의 컴포넌트들은 데이터 로딩이 끝날 때까지 `Loading...` 메시지 등을 표시한다 [1, 3]. 서버는 데이터가 해결(resolve)되는 대로 해당 Suspense 경계의 청크를 스트리밍하고, 클라이언트는 도착한 청크부터 점진적 하이드레이션(Progressive Hydration)을 시작한다 [3].
* **컴포넌트 지연 로딩(Lazy Loading) 구현:** React 애플리케이션의 초기 로드 시간을 향상시키기 위해 `React.lazy()`와 함께 활용된다 [2]. 필요한 시점에만 컴포넌트를 청크로 나누어 동적으로 불러오며, 불러오는 동안에는 `<Suspense fallback={<div>Loading...</div>}>`를 통해 에러나 빈 화면 대신 대기 UI를 제공한다 [2].
* **비동기 데이터 페칭의 병렬 처리:** React는 `await` 키워드를 통해 어떤 비동기 작업이 대기 중인지 파악한다 [1]. 컴포넌트 트리의 형제 노드(Sibling nodes)들이 각각 데이터를 요청할 경우, React는 이들을 병렬로 로드하여 성능을 최적화한다 [1].
* **클라이언트 데이터 페칭 라이브러리와의 통합:** `react-query``useSuspenseQuery` 훅과 결합하여 클라이언트 컴포넌트에서도 비동기 데이터 쿼리 상태를 선언적으로 관리할 수 있다 [6].
* **내부 동작 메커니즘:** Progressive Hydration의 내부 작동에서 Suspense는 주석 노드 마커(Comment node markers, 예: `<!--$-->`, `<!--$!-->`)를 통해 HTML 청크를 식별하고, 재시도 콜백(Retry callback) 메커니즘을 사용하여 클라이언트 DOM에 안전하게 통합된다 [7].
## ⚖️ Trade-offs & Caveats
* **라우팅 업데이트에 따른 UI 깜빡임 현상:** 클라이언트에서 `react-query` 등을 통해 데이터를 다룰 때, URL 쿼리 파라미터 변경(예: `window.history.pushState`)에 따라 데이터 페칭이 다시 발생하면, 기존 UI가 갑자기 사라지고 Suspense의 Fallback(로딩 화면) UI가 나타나는 매우 나쁜 사용자 경험이 발생할 수 있다 [8, 9]. 이를 방지하기 위해서는 상태 변경이나 라우팅을 `startTransition` 훅으로 감싸, 새 데이터가 준비될 때까지 기존 UI를 유지하도록 처리해야 한다 [6].
* **페칭 폭포수(Waterfall)로 인한 병목 현상:** 부모 컴포넌트와 자식 컴포넌트가 각각 독립적으로 데이터를 페칭할 때 부모-자식 간에 종속성이 있다면, 부모 데이터 페칭이 끝날 때까지 자식 컴포넌트의 페칭은 시작조차 할 수 없다 [10]. 이 폭포수 현상을 해결하려면 컴포넌트 트리 더 높은 곳에서 데이터를 로드한 뒤 하위 컴포넌트로 전달해야 한다 [10].
## 🔗 Knowledge Connections
### Related Concepts
#### [관계 유형 A (아키텍처/기반 기술)]
- [[React Server Components (RSC)]]
- 연결 이유: Suspense는 RSC 아키텍처에서 비동기 서버 컴포넌트 렌더링 시 아웃 오브 오더(Out-of-order) 스트리밍을 구현하기 위한 핵심 경계로 사용된다 [1, 11].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 서버에서 비동기로 데이터를 가져오면서도 초기 렌더링이 블로킹되지 않고 클라이언트로 화면을 스트리밍하는 메커니즘.
- [[Streaming SSR]]
- 연결 이유: SSR 환경에서 데이터를 모두 기다리는 대신, Suspense 경계를 기준으로 HTML 셸(Shell)을 우선 전송하고 나머지 부분은 청크 단위로 스트리밍하게 해준다 [3, 4].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 'Two-trip problem'을 완화하고 Time to Interactive (TTI)와 First Paint 성능을 향상시키는 원리.
#### [관계 유형 B (구현/활용 도구)]
- [[React.lazy()]]
- 연결 이유: 리액트 앱의 코드를 분할하고 지연 로드할 때 Suspense와 함께 필수적으로 사용되는 API이다 [2].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 클라이언트 사이드 자바스크립트 번들 크기를 줄여 애플리케이션 최적화를 이루는 기법.
- [[useSuspenseQuery]]
- 연결 이유: `react-query` 라이브러리에서 Suspense와 호환되도록 설계된 훅으로, 데이터 페칭 시 컴포넌트를 선언적으로 Suspend(일시 중지)시킨다 [6].
- 이 개념을 통해 더 깊게 이해할 수 있는 부분: 클라이언트 측에서 비동기 상태를 선언적이고 우아하게 처리하는 실전 패턴.
### Deeper Research Questions
- React의 내부 엔진(Reconciler 및 Fiber)은 비동기 작업 발생 시 Suspense 경계로 렌더링을 일시 중지하고 어떻게 재개하는가?
- Progressive Hydration 상황에서 React는 `<!--$-->`와 같은 주석 노드 마커를 활용해 어떻게 서버 청크를 기존 DOM 트리에 병합하는가?
- 중첩된 Suspense 컴포넌트 환경에서 `startTransition` API는 UI Fallback 표시를 어떻게 억제하고 이전 상태를 화면에 유지하는가?
- 대규모 애플리케이션에서 여러 데이터를 병렬로 요청할 때 발생하는 'Data Fetching Waterfall'을 방지하기 위한 아키텍처 레벨의 해결책은 무엇인가?
- RSC 환경에서 Suspense를 남용할 경우 자바스크립트 번들링 및 청크 전송 과정에 발생하는 오버헤드나 부작용은 없는가?
### Practical Application Contexts
- **Implementation:** `React.lazy()`를 사용해 무거운 UI 컴포넌트나 라우트를 분할할 때 `<Suspense>`로 감싸고, 로딩 스피너나 스켈레톤 UI를 `fallback`으로 전달하여 사용성을 높인다 [2].
- **System Design:** 대시보드나 이커머스 상세 페이지 같이 여러 백엔드 API 호출이 필요한 화면을 설계할 때, 전체 페이지 로딩을 막기 위해 각 컴포넌트 블록을 Suspense로 감싸 병렬 및 점진적 렌더링 아키텍처를 구성한다 [1, 4].
- **Operation / Maintenance:** `react-query``useSuspenseQuery` 등을 사용하여 데이터 페칭 로직의 로딩 상태(isLoading 등)를 컴포넌트 내부의 if문에서 제거하고, 부모 레벨로 위임하여 코드를 깔끔하게 유지보수한다 [6].
- **Learning Path:** 리액트의 기본 생명주기 및 훅 규칙 -> `React.lazy`를 이용한 코드 분할 -> `Suspense`의 선언적 로딩 상태 관리 -> React 18의 동시성 모드(`startTransition`) -> Next.js의 RSC와 Streaming SSR 순서로 학습을 확장한다.
- **My Project Relevance:** 무거운 외부 라이브러리나 늦게 응답하는 API를 호출하는 페이지 영역에 Suspense를 도입하여 사용자가 빈 흰 화면(Blank Screen)을 보는 시간을 최소화하고, 초기 로딩 속도 지표(First Paint)를 최적화할 수 있다.
### Adjacent Topics
- [[Progressive Hydration (점진적 하이드레이션)]]
- 확장 방향: 전체 페이지가 한 번에 상호작용 가능해지기를 기다리지 않고, 도착한 HTML 청크부터 점진적으로 이벤트 리스너를 결합해 나가는 방식과 그 성능적 이점을 탐구.
- [[React Fiber & Concurrent Mode (동시성 모드)]]
- 확장 방향: Suspense가 단순히 로딩 UI를 띄우는 것을 넘어, React가 렌더링의 우선순위를 정하고 인터럽트 가능한 렌더링을 수행하게 만드는 엔진 레벨의 원리 분석.
---
*Last updated: 2026-05-03*