4. 로딩 UI와 스트리밍
특수 파일 loading.js를 사용하면 React Suspense를 활용하여 의미 있는 로딩 UI를 만들 수 있다. loading.js 파일을 사용하면 특정 경로(segment)의 콘텐츠가 로드되는 동안 서버에서 즉시 로딩 상태(instant loading state)를 표시된다. 렌더링이 완료되면 새 콘텐츠가 자동으로 교환된다.
🚀 즉각적인 로딩 상태(Instant Loading States)
즉각적인 로딩 상태란 네비게이션 시 즉각적으로 표시되는 대체 UI(fallback UI) 이다.
예를 들어, 스켈레톤(Skeleton)이나 스피너(Spinner)를 미리 렌더링하거나, 표지 이미지 또는 제목과 같은 중요한 정보를 먼저 표시하는 것이다.
이를 통해 사용자는 애플리케이션이 응답하고 있음을 인식할 수 있으며 더 나은 사용자 경험을 제공할 수 있다.
loading.js 파일 생성
경로 폴더 내부에 loading.js 파일을 추가하면 즉시 로딩 상태를 만들 수 있다.
예시: loading.tsx
export default function Loading() {
// 로딩 UI 내부에 원하는 컴포넌트를 추가할 수 있다.
return <LoadingSkeleton />;
}
폴더 내 loading.js
는 layout.js
안에서 자동으로 중첩되며, 해당 폴더의 page.js
및 모든 하위 요소를 <Suspense>
경계 내에서 감쌀 수 있다.
🔹 Good to know: loading.js
의 특징
✅ 네비게이션이 즉각적으로 이루어진다. (서버 중심 라우팅 (server-centric routing)에서도 가능)
✅ 네비게이션 중 다른 경로로 이동이 가능하며, 콘텐츠 로딩이 끝날 때까지 기다릴 필요가 없다.
✅ 새로운 경로 세그먼트가 로드되는 동안, 공유 레이아웃(Shared layouts)은 인터랙티브하게 유지된다.
🚀 Suspense를 이용한 Streaming
loading.js
외에도 Suspense Boundaries를 직접 추가하여 개별 UI 컴포넌트에 대해 로딩 상태를 관리할 수 있다. Next.js의 App Router는 Streaming + Suspense를 지원한다.
🔹 스트리밍이란?
스트리밍을 이해하려면 서버 사이드 렌더링(SSR, Server-Side Rendering) 의 제한점을 먼저 알아야 한다.
🔰 기존 SSR 방식 (Streaming 없이)
- 서버에서 페이지에 필요한 모든 데이터를 가져옴
- 데이터를 기반으로 HTML을 생성
- 생성된 HTML, CSS, JavaScript를 클라이언트로 전송
- 사용자는 비상호작용(non-interactive) 상태의 페이지를 보게 됨
- React가 UI를 하이드레이션(Hydration)하여 인터랙티브하게 만듦
⚠️ 문제점
서버는 모든 데이터를 가져온 후에야 HTML을 렌더링할 수 있으며, 클라이언트는 전체 코드가 다운로드될 때까지 대기해야 함
🚀 스트리밍 방식 (Streaming SSR)
스트리밍을 활용하면 HTML을 작은 청크(chunk)로 나누어 서버에서 클라이언트로 점진적으로 전송 가능.
이 방식에서는 중요도가 높은 UI 요소(예: 제품 정보, 레이아웃)는 먼저 렌더링되고, 중요도가 낮은 요소(예: 리뷰, 관련 상품)는 나중에 로드된다.
💡 스트리밍의 이점
- TTFB(Time To First Byte) 감소 → 첫 번째 바이트가 더 빠르게 도착
- FCP(First Contentful Paint) 개선 → 화면에 첫 번째 콘텐츠가 더 빠르게 표시됨
- TTI(Time to Interactive) 최적화 → 사용자가 더 빨리 상호작용 가능
Suspense를 활용한 예제
Suspense는 비동기 작업(예: 데이터 가져오기)이 완료될 때까지 대체 UI(스피너, 스켈레톤 등)를 표시한 후, 로딩이 끝나면 실제 콘텐츠로 대체한다.
app/dashboard/page.tsx
import { Suspense } from "react";
import { PostFeed, Weather } from "./Components";
export default function Posts() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
);
}
✅ Suspense 사용 시 장점
✔ Streaming SSR → HTML을 점진적으로 렌더링 가능
✔ Selective Hydration → React가 중요한 요소부터 우선적으로 상호작용 가능
🚀 SEO 최적화
Next.js는 generateMetadata
내부에서 데이터를 먼저 가져온 후 UI를 스트리밍하므로, <head>
태그가 포함된 첫 번째 스트리밍 응답이 보장된다.
또한, 스트리밍은 서버에서 렌더링되므로 SEO에 영향을 주지 않는다.
Google의 리치 결과 테스트(Rich Results Test) 도구를 사용하여 Google 크롤러가 페이지를 어떻게 인식하는지 확인할 수 있다.
🚀 상태 코드
1️⃣ 기본 개념
Next.js에서 스트리밍(Streaming) 방식으로 데이터를 보낼 때,
- 서버는 항상
200
상태 코드를 반환함 → "요청이 성공적으로 처리됨"을 의미 - 하지만 응답이 완전히 끝난 게 아니라, 데이터가 부분적으로 계속 전송됨
2️⃣ 에러 처리 방식
- 스트리밍 중에도 서버는 오류 정보를 포함한 데이터를 보낼 수 있음
- 예를 들어, redirect()나 notFound() 같은 함수 사용 가능
- 하지만 이미 200 응답 헤더를 보냈기 때문에, 상태 코드를 바꿀 수는 없음
- 즉, 중간에 오류가 발생해도 404나 500 같은 다른 상태 코드로 변경 불가능
3️⃣ SEO 영향 없음
- 상태 코드가
200
으로 고정되지만, - 검색 엔진 최적화(SEO)에는 영향을 주지 않음
🛠 예제
✅ 기본적인 200
응답 (일반적인 요청)
GET /page HTTP/1.1 200 OK Content-Type: text/html
<html>
<body>
Hello, World!
</body>
</html>
➡ 위 예제는 일반적인 응답으로, 200 OK
가 정상적으로 동작함.
✅ 스트리밍에서 200
상태 코드 반환
GET /streaming-page HTTP/1.1 200 OK Content-Type: text/html
<html>
<body>
<p>로딩 중...</p>
</body>
</html>
➡ 이렇게 일부만 먼저 보내고, 나머지를 차례대로 전송하는 방식이 스트리밍(Streaming)
✅ 문제: 중간에 오류 발생!
스트리밍 중에 notFound()
를 호출하면?
이미 200 OK
헤더가 전송되었기 때문에, 상태 코드 변경 불가!
대신, 내용 안에서 오류 메시지를 표시할 수 있음
GET /streaming-page HTTP/1.1 200 OK Content-Type: text/html
<html>
<body>
<p>로딩 중...</p>
<p>❌ 페이지를 찾을 수 없습니다.</p>
</body>
</html>
➡ 이런 식으로 클라이언트가 받은 데이터 안에서 오류를 표시해야 함
🎯 결론
- Next.js의 스트리밍 방식은 항상
200
상태 코드 반환 - 중간에
notFound()
나redirect()
를 호출해도 상태 코드를 변경할 수 없음 - 대신, 클라이언트가 받은 내용(HTML 또는 JSON)에서 오류를 표시해야 함
- 이 방식은 SEO에 영향을 주지 않음
🔮 정리
📌 loading.js를 활용하면 즉각적인 로딩 UI를 제공하여 사용자 경험을 향상할 수 있다.
📌 Suspense와 Streaming을 활용하면 SSR 성능을 개선하고, 페이지를 점진적으로 렌더링할 수 있다.
📌 Next.js의 최적화된 기능을 활용하면 네비게이션이 더욱 원활해지고, SEO에도 유리하다.
출처
https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
Routing: Loading UI and Streaming | Next.js
Built on top of Suspense, Loading UI allows you to create a fallback for specific route segments, and automatically stream content as it becomes ready.
nextjs.org
'웹 프로그래밍 > Next.js' 카테고리의 다른 글
[Next.js 공식문서 정리] Routing : 07. Dynamic Routes.md (0) | 2025.03.29 |
---|---|
[Next.js 공식문서 정리] Routing : 06. Route Groups (0) | 2025.03.29 |
[Next.js 공식문서 정리] Routing : 05. Redirecting (0) | 2025.03.29 |
[Next.js 공식문서 정리] Routing : 03. Error Handling (0) | 2025.03.29 |
[Next.js 공식문서 정리] Routing : 02. Linking and Navigating (0) | 2025.03.29 |
[Next.js 공식문서 정리] Routing : 01. Layouts and Templates (0) | 2025.03.28 |