[next 13] Loading UI and Streaming

dana·2023년 7월 8일
0

Next.js

목록 보기
13/13
post-thumbnail

Loading UI

loading.js 파일은 React suspense를 이용해 의미있는 로딩화면을 보여주기 위해 사용되는 파일

Instant Loading States

즉각적으로 사용자에게 보여지는 fallback UI
페이지에서 데이터 fetching이 발생하는 경우, 해당 페이지의 같은 폴더 내 위치한 loading.js 를 fallback UI 로 보여준다. (Suspense가 없어도)

import type { Category } from '#/app/api/categories/category';
import { getBaseUrl } from '#/lib/getBaseUrl';
import { SkeletonCard } from '#/ui/skeleton-card';
import { notFound } from 'next/navigation';

export default async function Page({
  params,
}: {
  params: { categorySlug: string };
}) {
  
  // 🍀 해당 데이터가 fetching 되는 동안 가장 가까운 상위 계층에 위치한 loading을 보여줌
  const res = await fetch(
    // We intentionally delay the response to simulate a slow data
    // request that would benefit from `loading.js`
    `${getBaseUrl()}/api/categories?delay=1000&slug=${params.categorySlug}`,
    {
      // We intentionally disable Next.js Cache to better demo
      // `loading.js`
      cache: 'no-cache',
    },
  );

  if (!res.ok) {
    // Render the closest `error.js` Error Boundary
    throw new Error('Something went wrong!');
  }

  const category = (await res.json()) as Category;

  if (!category) {
    // Render the closest `not-found.js` Error Boundary
    notFound();
  }

  return (
    <div className="space-y-4">
      <h1 className="text-xl font-medium text-gray-400/80">{category.name}</h1>

      <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
        {Array.from({ length: category.count }).map((_, i) => (
          <SkeletonCard key={i} />
        ))}
      </div>
    </div>
  );
}

loading.js도 page.js와 마찬가지로 함께 위치한 layout으로 감싸진 채 보여진다.

Next.js의 네비게이션은 즉각적이며, 탈취 가능해 화면이 다 로딩되지 않더라도 다른 화면으로 이동 가능하다.
공유된 레이아웃(layout.js)은 내부 요소가 로딩될 동안 (완전히 렌더된 상태가 아니더라도) 인터랙션이 가능하다.

Streaming with suspense

next 13의 주요 기능 중 하나

UI의 렌더링된 단위를 점진적으로 렌더링하고 클라이언트에 점진적으로 스트리밍하는 기능으로,
데이터가 필요없는 부분은 먼저 보여주고, 데이터 fetchiing이 필요한 부분은 데이터를 받아오기 전까지 fallback ui를 보여준다.


loading.js 말고도 해당 컴포넌트에 커스컴 suspense boundary 설정 가능하다.

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>
  )
}

What is streaming?

스트리밍에 대해 알기 위해선 SSR과 그 한계를 아는 것이 중요
SSR에서는 사용자가 페이지를 보고 상호작용하기 전에 완료해야하는 일련의 단계가 존재

  1. 페이지에 필요한 데이터를 서버로 부터 받아옴
  2. 서버는 페이지의 HTML을 렌더링함
  3. HTML, CSS, JS가 클라이언트로 보내짐
  4. HTML, CSS를 이용해 만들어진 유저와 상호작용하지 않는 UI들이 보여짐
  5. React의 hydrate를 통해 인터랙션이 활성화됨.

이러한 단계는 순차적이고 차단적이므로 서버는 모든 데이터를 가져온 후에만 페이지의 HTML을 렌더링할 수 있다. 클라이언트에서는 페이지의 모든 컴포넌트에 대한 코드가 다운로드된 후에만 React가 UI에 dydrate할 수 있다.

Streaming은 페이지의 HTML을 작은 청크로 나눈 뒤, 점진적으로 서버에서 클라이언트로 보낸다. 페이지의 부분 요소들이 모든 데이터를 기다릴 필요 없이 더 빠르게 렌더될 수 있다. 중요도에 따라 먼저 보내지고 hydration도 먼저 시작할 수 있게 된다. 결과적으로 큰 데이터를 가져올 때 생기는 blocking이나, TTFB, FCP, TTI 의 blocking을 최소화할 수 있다.

Suspense의 장점
1. Streaming server rendering
2. Selective Hydration

SEO

Streaming UI 전에 generateMetadata 의 데이터를 먼저 받아온다. 이건 stream된 첫번째 응답이 <head> 태그임을 보장한다.

스트리밍은 서버에서 렌더되므로 SEO에 영향을 미치지 않는다.

아래의 링크를 통해 구글 웹 크롤링이 어떻게 이뤄질지 확인할 수 있다.
https://search.google.com/test/mobile-friendly

profile
PRE-FE에서 PRO-FE로🚀🪐!

0개의 댓글