HJS

Caching

Next.js의 가장 핵심적인 기능 중 하나는 Caching입니다. Next.js는 다양한 캐싱 전략을 통해 페이지 로딩 속도를 향상시키고, 서버 부하를 줄이며, 효율적인 데이터 관리를 제공합니다.

💡 Next.js의 캐싱 방식
Next.js는 크게 두 가지 방식으로 캐싱을 수행합니다.

이 두 가지 방식 fetch 함수를 기반으로 동작하며, Next.js의 fetch API는 브라우저의 fetch API를 확장한 기능을 제공합니다.

1️⃣ Full Route Cache

Next.js는 빌드 시점에 페이지를 렌더링하고 그 결과를 캐싱하는 Full Route Cache 기능을 제공합니다. 이 방식은 SSG(Static Site Generation)와 함께 동작하며, 미리 생성된 HTML과 데이터를 빠르게 제공하여 페이지 로딩 속도를 최적화합니다.

🔹 동작 방식

  1. React Server Component Payload 생성
    서버에서 React Server Component를 렌더링 하고, 스트리밍에 최적화된 데이터 형식으로 변환합니다.

  2. HTML 생성
    Next.js는 생성된 *Payload와 클라이언트 컴포넌트의 JavaScript를 결합하여 최종 HTML을 완성합니다.

  3. 캐싱 적용
    빌드 시점에 생성된 HTML이 CDN에 배포되고, 이후 동일한 페이지 요청이 발생하면 캐시된 HTML을 반환합니다.

💡 Payload
Next.js에서 React Server Component Payload 는 서버에서 렌더링된 컴포넌트의 데이터와 상태 정보를 포함한 특별한 형식의 데이터입니다. 이 데이터를 기반으로 클라이언트에서 HTML을 최종적으로 생성하게 됩니다.

🔹 Full Route Cache 무효화 (Revalidation)

데이터가 변경되었거나 실시간 정보가 필요한 경우, revalidate 옵션을 통해 캐시를 무효화할 수 있습니다. (IRS)

const data = await fetch('https://api.example.com/data', {
  next: { revalidate: 60 }, // 60초마다 캐시 갱신
});



2️⃣ Data Cache

Data Cache는 fetch 요청을 통해 가져온 API 데이터를 캐싱하는 방식입니다. 이 방식은 API 요청 수를 줄이고 응답 속도를 높이기 위해 사용됩니다.

🔹 동작 방식

// default
const res = await fetch('https://api.example.com/data'); // { cache: "force-cache" }와 동일
const data = await res.json();

// 데이터 캐싱 (3600초 동안 유지)
const res = await fetch('https://api.example.com/data', {
  next: { revalidate: 3600 },
});
const data = await res.json();

// 캐싱 없이 항상 새로운 데이터를 가져오기
const res = await fetch('https://api.example.com/data', {
  cache: 'no-store',
});
const data = await res.json();



3️⃣ Request Memoization

Request Memoization은 서버 컴포넌트 렌더링 중 동일한 fetch 요청이 여러 번 발생해도, 실제 네트워크 요청은 한 번만 실행되도록 최적화하는 기능입니다.

async function getCommonData() {
  const res = await fetch('https://api.example.com/common-data');
  return res.json();
}

const dataA = await getCommonData();
const dataB = await getCommonData(); // 두 번째 호출에서는 첫 번째 결과를 재사용

✔️ 이 기능은 서버 컴포넌트의 렌더링 과정에서만 유지되며, 요청이 완료되면 캐시는 초기화됩니다.




4️⃣ Next.js 캐싱 관련 주요 메서드

🔹 generateStaticParams

정적 경로를 생성하여 빌드 시점에 캐싱을 적용할 수 있습니다.

export async function generateStaticParams() {
  const posts = await fetch('https://api.example.com/posts').then((res) => res.json());
  return posts.map((post) => ({ slug: post.slug }));
}

export default function Page({ params }) {
  const { slug } = params;
}

✔️ generateStaticParams는 동적 경로를 미리 생성하여 정적 페이지로 빌드할 수 있도록 도와줍니다.

🔹 tags

특정 데이터에 태그를 부여하여 캐시를 관리할 수 있습니다.

fetch('https://api.example.com/products', {
  next: {
    revalidate: 60, // 60초마다 갱신
    tags: ['product', 'category'],
  },
});

✔️ 태그를 활용하면 특정 데이터 그룹을 손쉽게 캐시 무효롸할 수 있습니다.

🔹 revalidate

ISR(Incremental Static Regeneration) 방식으로 캐시를 일정 주기로 갱신합니다.

fetch('/api/data', {
  next: { revalidate: 10 },
});

✔️ revalidate를 사용하면 페이지나 데이터의 자동 갱신 주기를 설정할 수 있습니다.

🔹 revalidateTags

태그를 기반으로 특정 데이터를 무효화하고 갱신합니다.

import { revalidateTag } from 'next/cache';

async function updateProduct() {
  revalidateTag('product');
  return { message: 'Product data updated' };
}

✔️ revalidateTag는 특정 태그에 연결된 데이터를 즉시 갱신할 때 유용합니다.

🔹 revalidatePath

특정 경로의 Full Route Cache를 무효화하고 갱신할 수 있습니다.

import { revalidatePath } from 'next/cache';

async function updatePage() {
  revalidatePath('/products');
  return { message: 'Product page cache updated' };
}

✔️ revalidatePath('/경로')를 사용하면 해당 경로의 정적 페이지가 다시 생성됩니다.
✔️ 주로 SSG(Static Site Generation) 및 ISR(Incremental Static Regeneration)에서 활용됩니다.
✔️ 데이터 변경 시 전체 페이지를 갱신할 필요 없이 특정 경로만 갱신할 수 있어 효율적입니다.