[Next.js] Caching

 

Next.js는 대부분의 영역에서 fetch 함수를 기반으로 캐싱을 한다!

Next.js의 fetch는 브라우저 API가 아닌 Next.js에서 확장한 새로운 API다.

그 중에서도 크게 두가지 포인트에서 캐싱을 진행하게 된다.

 

Next.js의 두가지 캐싱 포인트

Full Route Cache (build 시)

- 빌드 시점에 페이지를 렌더링하고 그 결과를 캐싱하는 기능

- 서버는 매 요청마다 페이지를 다시 렌더링할 필요 없이, 미리 생성된 HTML과 데이터를 빠르게 제공할 수 있어 페이지 로딩속도가 크게 향상됨

- 서버에서 React의 API를 활용하여 렌더링 작업을 수행함

- 기본적으로 Full Route Cache는 지속적이며, 사용자 요청에 의한 렌더링 결과가 캐싱되어 있음

- 따라서 동일한 페이지에 대한 요청이 있을 때마다 서버가 빠르게 응답할 수 있는 것

- 하지만 데이터가 변경되거나, 실시간 정보가 필요한 페이지의 경우 이 캐시를 무효화하거나 동적 렌더링을 선택할 수 있음 ( revalidate 옵션 등의 기능을 통해 제어)

 

1) React Server Component Payload 생성

- React는 서버 컴포넌트들을 스트리밍에 최적화된 특별한 데이터 형식으로 렌더링

- 이 데이터는 클라이언트에서 사용할 컴포넌트의 정보와 상태를 포함

 

2) HTML 생성

- Next.js는 Payload와 클라이언트 컴포넌트의 JS 코드를 사용해 서버에서 최종 HTML을 생성

Data Cache (요청할 때)

- Next.js의 fetch는 브라우저의 fetch API를 확장한 것으로, 서버 측에서 각 요청에 맞는 캐싱 전략을 설정할 수 있음

- 기본적으로 fetch 함수를 사용하면 데이터가 자동으로 캐싱되며, 이는 동일한 데이터에 대한 중복 요청을 방지

- fetch 함수를 기반으로 데이터를 캐싱하여, 서버 요청 간에도 데이터를 지속적으로 활용할 수 있게 함

- 이는 외부 데이터 소스에 대한 요청 수를 줄이고, 응답 시간을 개선하는 데 큰 도움이 됨

 

const res = await fetch('<https://api.example.com/data>', { next: { revalidate: 3600 } });
const data = await res.json();

- 위는 3600초(1시간)동안 재검증 없이 캐시된 데이터를 사용하도록 설정한 것

 

const res = await fetch('<https://api.example.com/data>', { cache: 'no-store' });
const data = await res.json();

- 특정 데이터를 캐싱하지 않고 매번 최신 데이터를 가져오고 싶다면, 다음과 같이 옵션을 설정할 수 있음

- 페이지에 no-store 옵션의 fetch 함수가 하나라도 있으면 해당 페이지는 정적 페이지로 처리되지 않는다

 

 

Request Memoization

서버 컴포넌트 렌더링 중 동일한 fetch 요청이 여러번 호출되더라도, 실제로는 한번만 실행되도록 하는 기능

불필요한 중복 네트워크 요청을 방지하고, 서버 자원과 응답 시간을 최적화할 수 있음

 

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

// 컴포넌트 A에서 데이터 호출
const dataA = await getCommonData();

// 컴포넌트 B에서 동일한 데이터 호출
const dataB = await getCommonData();

위처럼 동일한 fetch 요청을 하는 경우, 두번째 호출에서는 첫번째 호출의 결과를 재사용하게 됨

 

 

Next.js 캐싱 메서드

generateStaticParams

- 빌드 타임에 모든 동적 경로에 해당하는 페이지를 미리 생성할 수 있도록 Next.js에 알려 빠른 페이지 로드와 서버 부담을 줄이기위한 목적!

 

예시) 제품 id로 동적 경로가 있을 때, generateStaticParams를 사용 -> 데이터를 받아와 반복문으로 모든 products의 id로 모든 상세 페이지를 미리 빌드할 수 있도록 했다

// app/products/[id]/page.tsx
import { getProducts } from '@/lib/api'; // 제품 데이터를 가져오는 가상의 함수

// generateStaticParams 함수 정의
export async function generateStaticParams() {
  const products = await getProducts(); // 모든 제품 데이터를 가져온다고 가정

  return products.map((product) => ({
    id: product.id, // 각 제품의 ID를 사용해 경로 파라미터 생성
  }));
}

// 동적 페이지 컴포넌트
export default function ProductPage({ params }: { params: { id: string } }) {
  return <div>Product ID: {params.id}</div>;
}

tags

Next.js에서 캐시된 데이터를 식별하고 관리하기 위해 사용하는 개념

특정 데이터나 페이지에 태그를 부여하여, 해당 태그와 관련된 데이터를 효율적으로 무효화할 수 있음

fetch('/api/data', {
  next: {
    revalidate: 60,
    tags: ['product', 'category']
  }
})

 

위 예시는 '/api/data' 에대한 요청을 product, category 태그를 붙인 예시이다.

기본적으로 캐시된 데이터를 사용하지만, 필요한 경우 revalidateTag('category') 혹은 revalidateTag('product') 메서드를 호출해 캐시된 데이터를 무효화하고 fetch 요청을 하여 유효한 데이터를 새로 받아올 수 있다.

 

+ revalidatePath 메서드를 사용하면 페이지 전체의 캐시를 무효화하고 새로 요청을 보내 유효한 값을 받아올 수 있다.

 

 

'Next.js' 카테고리의 다른 글

[Next.js] Auth와 Middleware  (0) 2024.09.30
[Next.js] Parallel Routes & Intercepting Routes  (1) 2024.09.29
[Next.js] Router Handler & Server Action  (0) 2024.09.27
[Next.js] Asset 최적화  (1) 2024.09.27
[Next.js] Error UI, Error Handling  (0) 2024.09.27