본문 바로가기

넥스트

[next.js] 6. 로딩 UI 와 스트리밍

반응형
next.js13 공식 문서 영문을 번역한 내용을 토대로 작성됩니다. 자세한 내용은 공식 사이트를 참고 하세요

 

 로딩 UI와 스트리밍

특별한 파일인 loading.js를 사용하여 React Suspense와 함께 의미 있는 로딩 UI를 생성할 수 있습니다. 이 규칙을 사용하면 라우트 세그먼트의 내용이 로드될 때 즉시 로딩 상태를 서버에서 표시할 수 있습니다. 새로운 내용은 렌더링이 완료되면 자동으로 교체됩니다.

 


  로딩 UI

   즉시 로딩 상태

즉시 로딩 상태는 탐색 시 즉시 표시되는 대체 UI입니다. 스켈레톤 및 스피너와 같은 로딩 표시자나 커버 사진, 제목 등의 미래 화면의 작은 but 의미 있는 부분을 사전 렌더링할 수 있습니다. 이를 통해 사용자가 앱이 응답하는 것을 이해하고 더 나은 사용자 경험을 제공할 수 있습니다.

로딩 상태를 만들려면 로딩.js 파일을 폴더 내에 추가하면 됩니다.

https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming




app/dashboard/loading.tsx

export default function Loading() {
// 로딩 내에 로딩 스켈레톤과 같은 UI를 추가할 수 있습니다.
return <LoadingSkeleton />
}

동일한 폴더 내에서 loading.js는 layout.js 내에 중첩됩니다. 이로써 자동으로 page.js 파일과 하위 모든 항목을 <Suspense> 경계로 래핑합니다.

 

(개인정리) 루트 레이아웃.js 파일이 존재한다고 할때 같은 경로에 있는 page.js 와 loading.js 는 layout.js 내에 중첩된다. 또한, page.js와 loading.js 는 Suspense 컴포넌트에 감싸진 형태로 존재하는데, fallback 에 등록된 loading.js 파일이 우선 클라이언트에게 보여지고, page.js 의 준비가 끝나면 loading.js 는 page.js로 대체된다.

 

알아두면 좋은 사항:
서버 중심의 라우팅이라도 탐색은 즉시 발생합니다.
라우트의 내용이 완전히 로드되기 전에 다른 라우트로 탐색할 필요가 없으므로 탐색이 중단 가능합니다.
공유 레이아웃은 새로운 라우트 세그먼트가 로드되는 동안 상호작용 가능한 상태를 유지합니다.

추천: Next.js는 이 기능을 최적화하기 위해 라우트 세그먼트(레이아웃 및 페이지)에 대해 loading.js 규칙을 사용하세요.

 


  스트리밍과 Suspense

loading.js 외에도 사용자 고유의 UI 컴포넌트에 대해 수동으로 Suspense 경계를 생성할 수 있습니다. App Router는 Node.js 및 Edge 런타임 모두에 대해 스트리밍과 Suspense를 지원합니다.

 

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

React 및 Next.js에서 스트리밍 작동 방식을 이해하기 위해서는 서버 측 렌더링(Server-Side Rendering, SSR)과 그 제한 사항을 이해하는 것이 도움이 됩니다.

 


SSR에서 사용자가 페이지를 보고 상호작용할 수 있는 상태가 되려면 일련의 단계를 완료해야 합니다:

1. 먼저, 특정 페이지의 모든 데이터가 서버에서 가져와집니다.
2. 그런 다음 서버는 페이지의 HTML을 렌더링합니다.
3. 페이지의 HTML, CSS 및 JavaScript가 클라이언트로 전송됩니다.
4. 생성된 HTML 및 CSS를 사용하여 비대화식 사용자 인터페이스가 표시됩니다.
5. 마지막으로, React가 사용자 인터페이스를 하이드레이션하여 상호작용 가능하게 만듭니다.

 


이러한 단계는 순차적이고 블로킹적입니다. 즉, 서버는 모든 데이터를 가져온 후에만 페이지의 HTML을 렌더링할 수 있습니다. 그리고 클라이언트에서는 React가 페이지의 모든 컴포넌트 코드를 다운로드한 후에야 사용자 인터페이스를 하이드레이션할 수 있습니다.

 

React와 Next.js에서 SSR은 사용자가 가능한 빨리 비대화식 페이지를 볼 수 있도록 도와줍니다.

 

스트리밍을 통해 페이지의 HTML을 더 작은 청크로 나누고 이러한 청크를 서버에서 클라이언트로 점진적으로 전송할 수 있습니다.

(개인 정리) 일반적인 서버 사이드 렌더링에서는 서버 측에서 모든 컴포넌트가 준비된 이후에 클라이언트에게 한 번에 파일을 전송한다. 그렇기 때문에, 클라이언트 측에서는 서버에서 파일을 넘겨 받고, 다운로드 하여 렌더링 하기 까지 사용자는 빈 화면을 볼 수 밖에 없다. 그러나, 스트리밍 방식을 사용하면, 모든 데이터가 준비되어 있지 않아도 데이터를 청크 단위로 나눠 클라이언트로 보내주기 때문에 사용자는 일부 준비된 데이터를 즉시 다운로드하여 브라우저 화면 상에서 접할 수 있게 된다.

 

  스트리밍 작동 방식

이를 통해 페이지의 일부를 더 빨리 표시할 수 있으며 모든 데이터가 로드되기를 기다릴 필요가 없습니다.

스트리밍은 React의 컴포넌트 모델과 잘 어울립니다. 각 컴포넌트는 청크로 간주할 수 있습니다. 우선순위가 높은 컴포넌트(예: 제품 정보) 데이터에 의존하지 않는 컴포넌트(예: 레이아웃)를 먼저 보낼 수 있으며 React는 조기에 하이드레이션을 시작할 수 있습니다. 우선순위가 낮은 컴포넌트(예: 리뷰, 관련 제품)는 데이터를 가져온 후에 같은 서버 요청에서 보낼 수 있습니다.

스트리밍은 페이지가 렌더링을 차단하지 않도록 긴 데이터 요청을 방지하려는 경우에 특히 유용합니다. 이로써 Time To First Byte (TTFB) 및 First Contentful Paint (FCP)를 줄일 수 있습니다. 또한 느린 장치에서 특히 Time to Interactive (TTI)를 개선하는 데 도움이 됩니다.

 

    예시

<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를 사용하면 다음과 같은 이점을 얻을 수 있습니다:

스트리밍 서버 렌더링 - 서버에서 클라이언트로 HTML을 점진적으로 렌더링합니다.
선택적 하이드레이션 - 사용자 상호작용을 기반으로 어떤 컴포넌트를 먼저 상호작용 가능하게 만들지 React가 우선순위를 정합니다.

Suspense의 추가 예시 및 사용 사례에 대해서는 React 문서를 참조하세요.

 

  SEO

Next.js는 generateMetadata 내부의 데이터 가져오기가 완료될 때까지 클라이언트로 UI를 스트리밍하기 전에 기다립니다. 이로써 스트리밍 응답의 첫 부분에 <head> 태그가 포함되도록 보장합니다.


스트리밍은 서버 렌더링이므로 SEO에 영향을 미치지 않습니다. Google의 웹 크롤러가 보는 페이지 모습 및 직렬화된 HTML(소스)을 확인하기 위해 Google의 모바일 친화성 테스트 도구를 사용할 수 있습니다.

 


 상태 코드

스트리밍 시, 요청이 성공했음을 나타내기 위해 200 상태 코드가 반환됩니다.

서버는 여전히 리디렉션이나 notFound와 같은 상황에서 클라이언트에게 문제 또는 오류를 전달할 수 있습니다. 응답 헤더는 이미 클라이언트로 전송되었기 때문에 응답 상태 코드를 업데이트할 수 없습니다. 이것은 SEO에 영향을 미치지 않습니다.

반응형