🎉 berenickt 블로그에 온 걸 환영합니다. 🎉
Front
NextJs
04-로딩UI와 Streaming

Loading UI and Streaming

특수 파일 loading.js를 사용하면 React Suspense로 의미 있는 로딩 UI를 만들 수 있습니다. 이 규칙을 사용하면 경로 세그먼트의 콘텐츠가 로드되는 동안 서버에서 instant loading state를 표시할 수 있습니다. 렌더링이 완료되면 새 콘텐츠가 자동으로 교체됩니다.

Loading UI and Streaming


1. 순간 로딩 상태

순간 로딩 상태(Instant Loading States)는 경로탐색 시 즉시 표시되는 fallback UI입니다. 스켈레톤과 스피너 같은 로더 또는 표지, 제목 등 화면의 작지만 의미 있는 부분을 미리 렌더링할 수 있습니다. 이를 통해 사용자가 앱이 응답하고 있음을 이해하고 더 나은 사용자 경험을 제공할 수 있습니다.

폴더 안에 loading.js 파일을 추가해서 로딩 상태를 만들 수 있습니다.

Loading UI and Streaming

app/dashboard/loading.tsx
1
export default function Loading() {
2
// 스켈레톤을 포함하여 Loading 함수 내부에 어떤 UI도 추가할 수 있습니다.
3
return <LoadingSkeleton />
4
}

같은 폴더에서 loading.jslayout.js 안에 중첩됩니다. 그러면 자동으로 <Suspense> 영역 안에 page.js 파일과 하위 자식을 감싸줍니다.

Loading UI and Streaming

참고

  • server-centric routing을 이용한 탐색은 즉시 이루어집니다.
  • 탐색은 중단할 수 있으며, 이는 새로운 Route의 모든 내용이 완전히 로드될 필요 없이 다른 Route로 넘어갈 수 있음을 의미합니다.
  • 새로운 라우트 세그먼트들이 로드되는 동안에도 공유 레이아웃은 상호 작용이 가능합니다.

추천: 라우트 세그먼트(layouts and pages)들에 loading.js규칙을 사용하세요. Next.js는 이 기능을 최적화합니다.


2. Suspense를 이용한 스트리밍

loading.js뿐 아니라 UI 구성 요소에 대한 Suspense Boundaries를 수동으로 만들 수도 있습니다. App 라우터는 Node.js와 Edge runtimes 모두에 대해 Suspense를 이용한 스트리밍을 지원합니다.


2.1 스트리밍이 무엇인가요?

React와 Next.js에서 스트리밍이 어떻게 작동하는지 알아보려면 **Server-Side Rendering (SSR)**와 제한 사항에 대해 이해하는 것이 좋습니다.

SSR을 사용하면 사용자가 페이지를 보고 상호작용하기까지 다음과 같은 단계를 진행해야 합니다.

  1. 먼저 주어진 페이지의 모든 데이터를 서버에서 가져옵니다.
  2. 서버는 페이지의 HTML을 렌더링합니다.
  3. 페이지의 HTML, CSS, JavaScript를 클라이언트로 전송합니다.
  4. 생성된 HTML과 CSS를 사용하여 사용자가 상호작용할 수 없는 UI를 보여줍니다.
  5. 마지막으로 React hydrates는 사용자가 UI와 상호작용할 수 있도록 만들어 줍니다.

Loading UI and Streaming

이런 단계를 순차적으로 진행됩니다. 즉, 서버는 모든 데이터를 가져온 후에만 페이지에 대한 HTML을 렌더링할 수 있습니다. 그리고 클라이언트에서 모든 React 페이지 구성 요소들에 대한 코드가 다운로드된 이후 UI를 hydrate할 수 있습니다.

SSR을 사용하는 React와 Next.js는 사용자에게 상호작용할 수 없는 페이지를 표시함으로써 가시적인 로딩 성능을 향상합니다.

Loading UI and Streaming

그러나 페이지를 사용자에게 표시하기 전에 서버의 모든 데이터를 가져와야 하므로 속도가 느려질 수 있습니다.

Streaming을 사용하면 페이지의 HTML을 더 작은 청크 단위로 분리함으로써 서버에서 클라이언트로 청크들을 점진적으로 보낼 수 있습니다.

Loading UI and Streaming

이렇게 하면 UI를 렌더링하기 전에 모든 데이터가 로드될 때까지 기다리지 않고 페이지의 일부를 더 빨리 로드할 수 있습니다.

각 구성 요소는 청크로 간주할 수 있으므로 스트리밍은 React의 Component 모델과 잘 동작합니다. 우선순위가 높거나(e.g. 제품 정보) 데이터에 의존하지 않는 컴포넌트(e.g. 레이아웃)는 먼저 전송될 수 있으며, React는 hydration을 더 일찍 시작할 수 있습니다. 우선순위가 낮은 컴포넌트(e.g. 리뷰, 추천 상품)는 데이터를 가져온 후 동일한 서버 요청으로 전송할 수 있습니다.

Loading UI and Streaming

스트리밍은 Time To First Byte (TTFB)First Contentful Paint (FCP)를 줄일 수 있으므로, 긴 데이터 요청이 페이지 렌더링을 막는 것을 방지할 때 더 유용합니다. 또한 Time to Interactive (TTI)는 특히 성능이 낮은 장치에서 효과적입니다.


2.2 예시

<Suspense>는 비동기 동작(e.g. fetch 데이터)을 실행하는 컴포넌트 감싸고 동작이 진행되는 동안 fallback UI(e.g. 스켈레톤, 스피너)를 표시한 후 동작이 완료되면 컴포넌트를 교체합니다.

app/dashboard/page.tsx
1
import { Suspense } from 'react'
2
import { PostFeed, Weather } from './Components'
3
4
export default function Posts() {
5
return (
6
<section>
7
<Suspense fallback={<p>피드 로딩 중...</p>}>
8
<PostFeed />
9
</Suspense>
10
<Suspense fallback={<p>날씨 로딩 중...</p>}>
11
<Weather />
12
</Suspense>
13
</section>
14
)
15
}

Suspense를 사용하면 다음과 같은 이점이 있습니다.

  1. 스트리밍 서버 렌더링 - 서버에서 클라이언트로 HTML을 점진적으로 렌더링합니다.
  2. 선택적 Hydration - React는 사용자 상호 작용을 기준으로 상호 작용할 수 있게 만들 컴포넌트의 우선 순위를 설정합니다.

Suspense의 예시와 사용 사례에 대한 자세한 내용은 React 문서를 참고하세요.


2.3 SEO

  • Next.js는 generateMetadata 내부의 데이터를 가져올 때까지 기다렸다가 UI를 클라이언트로 스트리밍합니다.

    • 이렇게 하면 스트리밍된 응답의 첫 번째에 <head> 태그가 포함됩니다.
  • 스트리밍은 서버 렌더링이므로 SEO에 영향을 주지 않습니다.

    • Mobile Friendly Test를 사용하여 구글의 웹 크롤러에 페이지가 어떻게 표시되는지, 배포된 HTML (소스)을 확인할 수 있습니다.

2.4 Status Codes

스트리밍 시 요청이 성공했음을 알리는 200 상태 코드가 반환됩니다.

서버는 redirect또는 notFound과 같이 스트리밍된 콘텐츠 자체 내에서 오류나 문제를 클라이언트에 전달할 수 있습니다. 응답 헤더가 이미 클라이언트에 전송되었으므로 응답의 상태 코드는 업데이트할 수 없습니다. 이는 SEO에 영향을 미치지 않습니다.