학습 Next.js - Day 16 / Full Route Cache, 정적 페이지화

이유승·2024년 10월 9일

Next.js 학습

목록 보기
17/27



1. 풀 라우트 캐시Full Route Cache


  • Request Memoization에서 캐시가 저장되는 원리를 배웠지만, 사실은 1단계 더 설명해야하는 부분이 존재한다.

  • Next.js는 빌드 타임에 데이터 호출, 캐싱 등의 작업을 마치고 페이지의 생성 결과를 풀 라우트 캐시Full Route Cache에 저장하게 된다.

  • 실제 접속 요청이 들어오게 되면,풀 라우트 캐시Full Route Cache에 저장된 생성 결과를 HIT해준다. (미리 완성된 결과를 반환해준다는 면에서 SSG와 결과가 흡사하다.)



Next App의 페이지들의 정적/동적 구분법

  • 해당 페이지가 어떤 기능을 사용하느냐에 따라서, Next에서 자동으로 정적/동적 여부를 구분한다.

  • Server Component에만 해당된다. Cilent Component는 Next가 알아서 페이지 유형을 구분하지 않는다.

동적Dynamic Page
-> 페이지가 접속 요청을 받을 때 마다 변화가 생기거나 데이터가 달라질 경우.

  • 데이터 페칭이 캐시되지 않는 경우.
  • 동적 함수 (쿠키, 헤더, 쿼리스트링 등)을 사용하는 컴포넌트가 있는 경우.
    -> 응답값을 저장하지도 않고, 언제든 값이 변화할 수 있다.

정적Static Page
-> 동적Dynamic Page이 아닌 모든 페이지들.

  • 그리고 Full Route Cache는 정적 페이지에서만 동작한다.

  • Next에서는 되도록이면 Full Route Cache가 동작하는 정적 페이지로 구성하는 것을 추천한다.
    -> 물론, 동적 페이지를 반드시 사용해야하는 경우들이 있으니 상황에 따라 잘 구분하면 된다. (동적 페이지에서도 데이터 캐시나 리퀘스트 메모이제이션은 동작하기 때문.)



Revalidate

  • Full Route Cache도 revalidate가 가능하다.

  • 여기도 마찬가지로 지정 시간이 지난 뒤의 요청은, 우선 유효하지 않은 저장값을 반환한 다음에 서버에 요청을 보내서 데이터를 업데이트하게 된다.



빌드 타임과 쿼리스트링

  • useSearchParams()는 쿼리스트링의 값을 가져오기 위해 사용하는 Hook.

  • 그런데 빌드 타임에는 쿼리스트링이라는 것이 존재할 수가 없다. 따라서 빌드 타임에서 에러가 발생하게 된다.

import { ReactNode, Suspense } from "react";
import Searchbar from "../../components/searchbar";

export default function Layout({
  children,
}: {
  children: ReactNode;
}) {
  return (
    <div>
      <Suspense fallback={<div>Loading ...</div>}>
        <Searchbar />
      </Suspense>
      {children}
    </div>
  );
}
  • React.js의 내장 컴포넌트 Suspense를 사용하면 된다. (미결, 미완성이라는 뜻)

  • Suspense는 사전 렌더링 과정에서 배제되고, 오직 클라이언트에서만 렌더링 되도록 설정한다.

  • Suspense는 사전 렌더링 과정에서 '미완성' 상태로 간주한다. fallback 옵션에서 지정된 임시 UI만이 렌더링되고, Suspense 아래 배치된 컴포넌트에 필요한 요소들이 모두 갖추어진 뒤에 정식 렌더링을 실행하게 된다.

  • 학습 프로젝트 코드 기준으로 설명하면, Searchbar 컴포넌트에 필요한 쿼리스트링이 클라이언트에서 불러와지기 전까지 Suspense에 의해 렌더링이 배제된다.



2. 풀 라우트 캐시Full Route Cache 적용을 위한 정적 페이지화 방법

데이터 페칭이 캐시되지 않는 경우.

async function Footer() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`
  );

	(...)
}
  • 위 컴포넌트는 데이터 페칭의 결과가 캐시되지 않기 때문에 동적 페이지로 간주된다.
async function Footer() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`,
    { cache: "force-cache" }
  );

	(...)
}
  • 이런 경우라면 데이터 캐시를 사용해주기만 해도 페이지가 정적으로 전환된다.

  • 다만, 무작정 데이터 캐시를 사용하는 것도 좋은 개발 방법은 아니다. 데이터 캐시가 필요한 상황인지를 파악할 것!



동적 함수 (쿠키, 헤더, 쿼리스트링 등)을 사용하는 컴포넌트가 있는 경우

export default async function Page({
  searchParams,
}: {
  searchParams: {
    q?: string;
  };
}) {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/search?q=${searchParams.q}`,
    { cache: "force-cache" }
  );
  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>;
  }

  const books: BookData[] = await response.json();

  return (
    <div>
      {books.map((book) => (
        <BookItem key={book.id} {...book} />
      ))}
    </div>
  );
}
  • 이 페이지의 경우, searchParams라는 동적 함수가 포함되어 있고 이를 대체할 방법이 없기 때문에 정적 페이지로 만드는 것은 불가능하다.

  • 다만 여기는 동일한 검색 결과를 캐시하여 페이지를 최적화할 수는 있다.



3. 풀 라우트 캐시Full Route Cache 적용을 위한 정적 페이지화 방법 - 동적 경로에서의 적용

export default async function Page({
  params,
}: {
  params: { id: string | string[] };
}) {

	(...)
  
}  
  • 특정 책의 id 값을 받아서 데이터를 조회하여 렌더링하는 상세 페이지.

  • 이 페이지 또한 동적 함수를 대체할 방법은 없다.

  • 다만, 여기서의 동적 함수는 어떤 id값이 올지 모른다는 전제조건에서 실행되는 것.

  • 그렇다면 generateStaticParams() 메소드를 이용하여, 해당 페이지에 들어올 수 있는 데이터들을 사전에 알려주는 방법으로 정적 페이지화를 실현할 수 있다.

  • Next에서는 generateStaticParams()가 존재한다면, 이 정적 URL 파라미터를 이용해서 빌드 타임에 페이지들을 생성할 수 있게 된다.

  • generateStaticParams() 사용시에는 값을 반드시 문자열만 사용해야 하며, generateStaticParams()을 사용하게 되면 해당 페이지 컴포넌트는 데이터 캐시를 사용하지 않는 페칭이 있다라도 해도 정적 페이지로 간주된다.

  • generateStaticParams()에서 제공하지 않는 값에 해당하는 페이지는 동적 페이지로 생성된다. 이렇게 생성된 페이지는 동적이긴 하지만 Full Route Cache에 저장된다.



404 예외처리

  if (!response.ok) {
    if (response.status === 404) {
      notFound();
    }
    return <div>오류가 발생했습니다...</div>;
  }
  • generateStaticParams()에 없는 값에 해당하는 페이지가 동적으로 생성이 되긴 하지만, 아예 존재하지 않는 값은 당연히 에러가 발생하게 된다.

  • 따라서 이런 부분에 대해서는 따로 예외처리를 해주는게 좋다.



DynamicParams

	export const dynamicParams = false;
  • generateStaticParams()에서 지정하지 않은 값들은 모두 존재하지 않는다고 간주하고 싶다면, dynamicParams 변수를 생성해서 export내보내기 해주면 된다.









00. 강의 소개.

profile
프론트엔드 개발자를 준비하고 있습니다.

0개의 댓글