The Big Picture
// next.config.js
const config = {
experimental: {
// 새로운 캐싱 시스템 활성화. 이제 코드에서 `use cache` 사용 가능
dynamicIO: true,
// 선택사항: 캐시 프로파일 설정
cacheLife: {
blog: {
stale: 3600, // 클라이언트 캐시 유지: 1시간
revalidate: 900, // 서버에서 새로고침: 15분
expire: 86400, // 최대 수명: 1일
},
},
},
};
use cache 기본 사용법
// 1. 파일 단위 캐싱
"use cache";
export default function Page() {
return <div>Cached Page</div>;
}
// 2. 컴포넌트 단위 캐싱
export async function PriceDisplay() {
"use cache";
const price = await fetchPrice();
return <div>${price}</div>;
}
// 3. 함수 단위 캐싱
export async function getData() {
"use cache";
return await db.query();
}
태그 기반 캐싱
import { unstable_cacheTag as cacheTag, revalidateTag } from 'next/cache';
// 특정 데이터 그룹 캐싱
export async function ProductList() {
'use cache';
cacheTag('products');
const products = await fetchProducts();
return <div>{products}</div>;
}
// 데이터 변경 시 캐시 무효화
export async function addProduct() {
'use server';
await db.products.add(...);
revalidateTag('products');
}
사용자 정의 Cache 프로필
import { unstable_cacheLife as cacheLife } from "next/cache";
export async function BlogPosts() {
"use cache";
cacheLife("blog"); // 미리 정의한 블로그 캐시 프로필 사용
return await fetchPosts();
}
중요하지만 간과할 수 있는 사항
캐시 키 자동 생성
export async function UserCard({ id, onDelete }) {
"use cache";
// id는 캐시 키에 포함
// onDelete는 전달되지만 캐싱에는 영향을 주지 않음
const user = await fetchUser(id);
return <div onClick={onDelete}>{user.name}</div>;
}
동적 콘텐츠와 캐시 콘텐츠의 혼합
export async function CachedWrapper({ children }) {
"use cache";
const header = await fetchHeader();
return (
<div>
<h1>{header}</h1>
{children} {/* 동적 콘텐츠는 그대로 유지 */}
</div>
);
}
export async function ProductPage({ id }) {
"use cache";
cacheTag(["products", `product-${id}`, "featured"]);
// 이 태그들 중 어떤 것을 사용해도 무효화 가능
}
캐싱 계층 구조
"use cache";
export default async function Page() {
return (
<div>
<CachedHeader />
<div>
<Suspense fallback={<Loading />}>
<DynamicFeed /> {/* 동적 콘텐츠 */}
</Suspense>
</div>
</div>
);
}
타입 안전성
// 상수로 캐시 프로필 키를 관리
export const CACHE_LIFE_KEYS = {
blog: "blog",
} as const;
const config = {
experimental: {
cacheLife: {
[CACHE_LIFE_KEYS.blog]: {
stale: 3600,
revalidate: 900,
expire: 86400,
},
},
},
};
캐싱 태그를 효율적으로 관리하는 방법
export const CACHE_TAGS = {
blog: {
all: ["blog"] as const,
list: () => [...CACHE_TAGS.blog.all, "list"] as const,
post: (id: string) => [...CACHE_TAGS.blog.all, "post", id] as const,
comments: (postId: string) =>
[...CACHE_TAGS.blog.all, "post", postId, "comments"] as const,
},
} as const;
// 캐싱 태그 설정
function tagCache(tags: string[]) {
cacheTag(...tags);
}
// 사용 예제
export async function BlogList() {
"use cache";
tagCache(CACHE_TAGS.blog.list());
}