기억보단 기록을/Next JS (App Router)

[NextJS 13] Routing - Loading UI and Streaming

_OIL 2023. 6. 7. 21:39
반응형

loading.js 파일은 React Suspense를 자동으로 래핑하여 스트리밍 형태의 로딩 UI를 생성하는 데 도움을 줍니다. 이 컨벤션을 사용하면 라우트 세그먼트의 내용을 로드하는 동안 서버에서 즉시 로딩 상태를 표시하고, 렌더링이 완료되면 자동으로 새로운 콘텐츠로 교체됩니다.

Instant Loading States

인스턴트 로딩 상태는 탐색 시 즉시 표시되는 대체 UI입니다. 스켈레톤이나 스피너와 같은 로딩 표시기 또는 향후 화면의 작은 부분(커버 사진, 제목 등)과 같은 의미 있는 요소를 사전 렌더링하여 로딩 상태를 만들 수 있습니다. 이를 통해 사용자가 애플리케이션이 응답하고 있다는 것을 이해할 수 있으며, 더 나은 사용자 경험을 제공할 수 있습니다.

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

/* app/dashboard/loading.tsx */

export default function Loading() {
  // You can add any UI inside Loading, including a Skeleton.
  return <LoadingSkeleton />;
}

같은 폴더에서 loading.js는 layout.js 안에 중첩됩니다. <Suspense> 경계에서 page.js 파일과 그 아래의 모든 자식을 자동으로 래핑합니다.

알아두면 좋은 점:

서버 중심의 라우팅에서도 네비게이션은 즉시 이루어집니다.

  • 탐색은 중단 가능합니다. 즉, 다른 라우트로 이동하기 전에 라우트의 내용이 완전히 로드될 필요가 없습니다.
  • 새로운 라우트 세그먼트가 로드되는 동안 공유 레이아웃은 상호작용을 유지합니다.
💡 권장 사항: Next.js가 인스턴트 로딩 상태를 최적화하므로 라우트 세그먼트(레이아웃 및 페이지)에 loading.js 컨벤션을 사용해주세요

Streaming with Suspense

loading.js 외에도 직접 UI 컴포넌트에 대한 Suspense Boundary를 생성할 수도 있습니다. 앱 라우터는 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가 페이지의 모든 컴포넌트 코드를 다운로드한 후에만 UI를 하이드레이트할 수 있습니다.

React와 Next.js를 사용한 SSR은 사용자에게 비대화형 페이지를 가능한 빨리 표시함으로써 인식되는 로딩 성능을 향상시킵니다.

하지만, 페이지를 사용자에게 보여주기 전에 서버에서 모든 데이터 가져오기가 완료되어야 하기 때문에 여전히 느릴 수 있습니다.

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

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

스트리밍은 React의 컴포넌트 모델과 잘 작동합니다. 각 컴포넌트는 청크로 간주될 수 있습니다. 우선순위가 높은 컴포넌트(예: 제품 정보) 또는 데이터에 의존하지 않는 컴포넌트(예: 레이아웃)를 먼저 보냄으로써 React는 하이드레이션을 더 일찍 시작할 수 있습니다. 우선순위가 낮은 컴포넌트(예: 리뷰, 관련 제품)는 데이터를 가져온 후에 동일한 서버 요청에서 전송될 수 있습니다.

스트리밍은 페이지 렌더링을 차단하지 않고 긴 데이터 요청이 페이지를 방해하는 것을 방지하고자 할 때 특히 유용합니다. 이는 Time To First Byte (TTFB)와 First Contentful Paint (FCP)를 감소시킬 수 있습니다. 또한 느린 장치에서도 특히 Time to Interactive (TTI)를 개선하는 데 도움이 됩니다.

Example

<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는 UI를 클라이언트로 스트리밍하기 전에generateMetadata 내에서 데이터 가져오기가 완료될 때까지 기다립니다. 이는 스트리밍 응답의 첫 부분이 <head> 태그를 포함하도록 보장합니다.
  • 스트리밍은 서버에서 렌더링되기 때문에 SEO에 영향을 주지 않습니다. Google의 웹 크롤러가 페이지를 어떻게 보는지 확인하고 직렬화된 HTML(소스)을 볼 수 있도록 Google의 모바일 친화성 테스트 도구를 사용할 수 있습니다.

Playgroud

 

느낀점

  • loading.js 파일을 사용하면 React Suspense 를 자동으로 래핑 해주는게 정말로 편합니다.

참조

 

Routing: Loading UI and Streaming | Next.js

Using App Router Features available in /app

nextjs.org

 

반응형