ReactNextCentral

로딩 UI 및 스트리밍

Published on
Suspense 위에 구축된 로딩 UI를 통해 특정 라우트 세그먼트에 대한 대체 UI를 만들고 준비되면 자동으로 내용을 스트리밍 할 수 있습니다.
Table of Contents

특별한 파일 loading.js리액트 Suspense와 함께 의미 있는 로딩 UI를 만드는 데 도움을 줍니다. 이 규칙을 사용하면 라우트 세그먼트의 내용이 로딩되는 동안 서버에서 즉시 로딩 상태를 표시할 수 있습니다. 렌더링이 완료되면 새로운 내용이 자동으로 교체됩니다.

"로딩 UI"


즉시 로딩 상태

즉시 로딩 상태는 탐색 즉시 표시되는 대체 UI입니다. 스켈레톤, 스피너와 같은 로딩 지시자나 표지 사진, 제목 등의 미래의 화면의 작지만 의미 있는 부분을 사전 렌더링 할 수 있습니다. 이로써 사용자는 앱이 응답 중임을 이해하게 되며 사용자 경험이 향상됩니다.

폴더 내에 loading.js 파일을 추가하여 로딩 상태를 생성합니다.

"loading.js 특별한 파일"

app/dashboard/loading.tsx
export default function Loading() {
  // 로딩 내에서 스켈레톤을 포함한 어떠한 UI도 추가할 수 있습니다.
  return <LoadingSkeleton />
}
JavaScript
app/dashboard/loading.js
export default function Loading() {
  // 로딩 내에서 스켈레톤을 포함한 어떠한 UI도 추가할 수 있습니다.
  return <LoadingSkeleton />
}

동일한 폴더에서 loading.jslayout.js 내부에 중첩됩니다. 이것은 자동으로 <Suspense> 경계 안에서 page.js 파일 및 그 아래의 모든 자식을 감쌉니다.

"loading.js 개요"

  • 탐색은 즉시 이루어지며 서버 중심 라우팅에도 불구하고 즉시 이루어집니다.
  • 탐색은 중단 가능하며 다른 라우트로 이동하기 전에 라우트의 내용을 완전히 로드할 필요가 없다는 것을 의미합니다.
  • 새로운 라우트 세그먼트가 로드되는 동안 공유 레이아웃은 상호 작용 가능한 상태로 유지됩니다.
추천

Next.js에서 이 기능을 최적화하므로 라우트 세그먼트(레이아웃 및 페이지)에 loading.js 규칙을 사용하세요.


Suspense와 함께 스트리밍하기

loading.js 외에도 직접 UI 컴포넌트에 대한 Suspense 경계를 수동으로 생성할 수 있습니다. 앱 라우터는 Node.js와 Edge 런타임 모두에 대해 Suspense와 함께 스트리밍을 지원합니다.

스트리밍이란 무엇인가?

리액트와 Next.js에서 스트리밍이 어떻게 작동하는지 알아보기 위해 서버 사이드 렌더링(SSR) 및 그 제한 사항을 이해하는 것이 도움이 됩니다.

SSR을 사용하면 페이지를 볼 수 있고 상호 작용하기 전에 완료해야 할 일련의 단계가 있습니다.

  1. 먼저 서버에서 주어진 페이지의 모든 데이터를 가져옵니다.
  2. 서버는 페이지의 HTML을 렌더링합니다.
  3. 페이지의 HTML, CSS, JavaScript가 클라이언트에 전송됩니다.
  4. 생성된 HTML 및 CSS를 사용하여 상호 작용하지 않는 사용자 인터페이스가 표시됩니다.
  5. 마지막으로, 리액트는 사용자 인터페이스를 하이드레이트(hydrate)하여 상호 작용하게 만듭니다.

이 단계들은 순차적이며 블로킹되어 있어 모든 데이터가 가져와진 후에만 서버에서 페이지의 HTML을 렌더링 할 수 있습니다. 그리고 클라이언트에서는 페이지의 모든 컴포넌트 코드가 다운로드된 후에만 리액트가 UI를 가져와 처리 할 수 있습니다.

리액트와 Next.js의 SSR은 최대한 빨리 상호 작용하지 않는 페이지를 사용자에게 표시함으로써 perceived 로딩 성능을 개선하는 데 도움이 됩니다.

그러나 모든 데이터를 서버에서 가져와야 페이지를 사용자에게 보여줄 수 있기 때문에 여전히 느릴 수 있습니다.

스트리밍을 사용하면 페이지의 HTML을 더 작은 청크로 나누고 그 청크를 서버에서 클라이언트로 순차적으로 보낼 수 있습니다.

이를 통해 모든 데이터를 로드하기 전에 UI를 렌더링 할 수 없기 때문에 페이지의 일부를 더 빨리 표시할 수 있습니다.

스트리밍은 리액트의 컴포넌트 모델과 잘 어울립니다. 각 컴포넌트는 청크로 간주될 수 있습니다. 높은 우선 순위를 가진 컴포넌트(예: 제품 정보) 또는 데이터에 의존하지 않는 컴포넌트는 먼저 보내질 수 있으며(예: 레이아웃), 리액트는 더 일찍 가져와 처리를 시작할 수 있습니다. 낮은 우선 순위를 가진 컴포넌트(예: 리뷰, 관련 제품)는 해당 데이터가 가져와진 후 동일한 서버 요청에서 보낼 수 있습니다.

스트리밍은 긴 데이터 요청이 페이지 렌더링을 차단하는 것을 방지하려는 경우에 특히 유용합니다. 또한 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>피드 로딩 중...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>날씨 로딩 중...</p>}>
        <Weather />
      </Suspense>
    </section>
  )
}
JavaScript
app/dashboard/page.js
import { Suspense } from 'react'
import { PostFeed, Weather } from './Components'

export default function Posts() {
  return (
    <section>
      <Suspense fallback={<p>피드 로딩 중...</p>}>
        <PostFeed />
      </Suspense>
      <Suspense fallback={<p>날씨 로딩 중...</p>}>
        <Weather />
      </Suspense>
    </section>
  )
}

Suspense를 사용함으로써 다음의 이점을 얻을 수 있습니다.

  1. 스트리밍 서버 렌더링: 서버에서 클라이언트로 HTML을 점진적으로 렌더링합니다.
  2. 선택적 가져오기(Hydration): 리액트는 사용자 상호 작용을 기반으로 먼저 상호 작용 가능하게 할 컴포넌트를 우선합니다.

더 많은 Suspense 예제와 사용 사례에 대해서는 리액트 문서를 참조해 주세요.

SEO

  • Next.js는 UI를 클라이언트에 스트리밍하기 전에 generateMetadata 내에서 데이터 가져오기를 완료할 것입니다. 이로 인해 스트림 응답의 첫 부분에는 <head> 태그가 포함됩니다.
  • 스트리밍이 서버 렌더링되므로 SEO에 영향을 주지 않습니다. Google의 모바일 친화적 테스트 도구를 사용하여 Google의 웹 크롤러에게 어떻게 페이지가 표시되는지 확인하고 직렬화된 HTML을 볼 수 있습니다 (출처).

상태 코드

스트리밍할 때 200 상태 코드가 반환되어 요청이 성공적이었음을 나타냅니다.

서버는 스트리밍된 콘텐츠 내에서 redirect 또는 notFound를 사용할 때와 같이 클라이언트에게 오류나 문제를 전달할 수 있습니다. 응답 헤더가 이미 클라이언트에게 전송되었기 때문에 응답의 상태 코드를 업데이트할 수 없습니다. 이것은 SEO에 영향을 주지 않습니다.