Next.js의 SSR

문제 상황

Collection 페이지에서는 tanstack query를 통해서 데이터를 가져오고 있었다. 데이터를 가져오는 동안(status === "pending"), 스켈레톤이 보이도록 했다.

Lighthouse 성능 측정 결과, Largest Contentful Paint와 Speed Index에 대해 개선이 필요해보였다.

Next.js의 데이터 페칭

서버 컴포넌트에서는 간단히 비동기 함수를 사용해서 데이터를 가져올 수 있다.

const getInitialCollections = async (limit: number): Promise<CollectionItemType[] | undefined> => {
  // fetch data
}

const Page = async () => {
  const limit = 8;
  const initialCollectionData = await getInitialCollections(limit);

  return (
    <MainLayout>
      <CollectionList limit={limit} initialData={initialCollectionData} />
    </MainLayout>
  );
};

export default Page;
// useCollectionQuery.tsx
const {
  data,
  ...
} = useInfiniteQuery({
  ...
  initialData: initialData ? {
    pages: [initialData],
    pageParams: [0]
  } : undefined
});

데이터를 쿼리의 initialData로 넘겨주면, 클라이언트에서는 처음부터 데이터가 존재하게 된다. 따라서 query의 status에도 "pending"이 존재하지 않게 된다!

다시 성능 측정 결과, LCP와 speed index 모두 개선되었다.

다만 해당 페이지로 이동하는 시간이 조금 오래 걸리는 문제가 있다. 데이터 페칭하는 비동기 작업이 느려지면, 전체 페이지가 block된다는 문제가 있다.

이러한 문제를 해결하기 위해서, Streaming을 사용할 수 있다.

Streaming

페이지 HTML을 더 작은 chunk로 나누고 점진적으로 서버에서 클라이언트로 chunk를 보내는 것을 의미한다. 스트리밍을 적용하면, 데이터 페칭 작업 동안 페이지가 차단되지 않아 사용자는 데이터가 모두 로드되기 전에 페이지와 상호작용할 수 있다.

페이지 파일와 같은 폴더 내에 loading.tsx 파일을 만들어 데이터 페칭 작업 동안 보여줄 화면을 작성하면 된다.

실제로 loading 파일 안에 스켈레톤을 작성한 뒤, 측정한 성능 결과는 다음과 같았다.

아무래도 스켈레톤 때문에 LCP가 크게 나올 수 밖에 없었다. 해당 페이지의 경우 걸리는 시간이 너무 크진 않아서 문제가 없다고 생각되지만, 정말 정말 오래 걸리는 작업이라면 사용자의 경험을 고려하여 로딩 컴포넌트를 잘 작성해야 될 것 같다. 페이지가 차단되는 것 만큼 답답한 일은 없으니..

Last updated