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에서는 사용자가 페이지를 보고 상호작용할 수 있기 전에 일련의 단계가 수행됩니다:
- 해당 페이지에 대한 모든 데이터가 서버에서 가져옵니다.
- 서버는 페이지의 HTML을 렌더링합니다.
- 페이지의 HTML, CSS 및 JavaScript가 클라이언트로 전송됩니다
- 생성된 HTML과 CSS를 사용하여 비대화형 사용자 인터페이스가 표시됩니다.
- 마지막으로, 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 를 자동으로 래핑 해주는게 정말로 편합니다.
참조
'기억보단 기록을 > Next JS (App Router)' 카테고리의 다른 글
[NextJS 13] Routing - Parallel Routes (병렬 라우트) (0) | 2023.06.12 |
---|---|
[NextJS 13] Routing - Error Handling(에러처리) (0) | 2023.06.10 |
[NextJS 13] Routing - Dynamic Routes (0) | 2023.06.06 |
[NextJS 13] Routing - Route Groups (0) | 2023.06.04 |
[NextJS 13] Routing - Linking and Navigating (0) | 2023.06.03 |