캐싱
next.js에서 fetch GET요청은 쿠키, 헤더가 없을 시 자동으로 캐싱이 된다.
이외에도 next 서버액션에서 db 데이터를 캐싱하는 법을 알아보자!
- 캐싱(Caching)의 개념
: 서버로부터 받은 데이터를 메모리에 저장해 놓는 것
- 캐싱의 장점
: 저장한 정보를 재활용함으로써, 동일한 API를 반복해서 요청하는 상황을 줄인다.
즉, 화면에 빠르게 원하는 정보를 표시할 수있고, DB의 부담 또한 덜어 줄 수 있다.
unstable_cache
⇒ Next (14버전~) 캐싱함수.
- 사용방법
- 첫 번째 매개변수: action 함수 삽입 (db 통신 함수, return 해줘야 함)
- 두번째 매개변수: 캐시 키 배열 (action 당 unique)
- 기존의 action대신 호출해주면 됨. ⇒ return 값이 캐싱 되는 것
- unstable_cache 실행시 일어나는 일
- 첫 호출 : action 함수가 한번 실행됨. (db에 요청을 보내고 결과를 반환) & 데이터가 메모리에 캐싱됨
- 이후 호출 : db와의 통신 x, 첫번째 호출에서 캐시된 데이터를 반환
(ex. db에 저장된 Product이름을 바꿔주고 브라우저를 새로고침해도, 유저에게 보여지는 값은 바뀌지 않음)
import { unstable_cache } from 'next/cache'; const getPosts = unstable_cache(async () => { return await db.select().from(posts); //서버 액션 코드 }, ['posts'], { revalidate: 3600 }); const allPosts = await getPosts();
- 개발 모드 && 브라우저의 개발자 도구를 open한 상태라면 unstable_cache가 캐싱 된 데이터를 반환하지 않고 db에 접근하는 함수를 매번 실행함에 주의
새로운 데이터로 갱신하기
기본적으로 서버를 다시 시작하는 등 하지 않는 이상 데이터 갱신이 되지 않고 계속 캐쉬 데이터를 쓴다. ⇒ 데이터를 갱신해보자!
방법1. revalidate
옵션 (만료 시간 명시)
const getPosts = unstable_cache(async () => { //서버 액션 코드 }, [키], { revalidate: 3600 });
⇒ 페이지를 다시 “요청할 때”, revalidate 시간 만큼 지났다면 다시 호출 & revalidate 타이머가 다시 초기화. (지나지 않았다면 캐시 데이터 그대로)
⇒ 시간에 따라 자동으로 갱신되는 것이 아니라, 요청할 때 시간을 체크!
방법2. revalidatePath
함수 (캐쉬쓰지 않을 url 명시)
: revalidatePath 함수를 호출하면 해당 url에 나와있는 데이터들은 모두 새롭게 갱신
(페이지 전체가 다시 빌드)
import {revlaidatePath} from "next/cache" const revalidate = async () => { //서버액션 함수 "use server" revlaidatePath("/home") } return <form action={revalidate}>...</form>
방법3. revalidateTag
: 태그를 이용해 특정 서버액션만 캐시를 쓰지 않게 한다.
const revalidate = unstable_cache(getPosts, [키], { tags: [태그] }); const getPosts = async () => { "use server" revalidateTag(태그) } ... return <form action={revalidate}>...
- 태그는 unique하지 않아도 됨 ⇒ 해당 태그를 가진 모든 액션이 데이터 갱신!
fetch cache
next.js에서 fetch는 자동으로 캐싱이 된다.
- fetch cache 조건
- GET 요청
- 쿠키, 헤더가 없음
- server action 내의 fetch가 아님
⇒ 이 조건에 만족하지 않는데 캐시를 적용하고 싶다면 ? unstable_cache를 쓰자
- 옵션은 앞서 unstable_cache와 똑같이 적용할 수 있다.
fetch("~", { next:{ revalidate: 60, //최소 60초 지나야 갱신 tags: [""] //revalidateTag(태그)로 갱신 } } ) // revalidatePath도 똑같이 가능
Production Cache
npm run start
: production으로 서버 실행- 보는 사용자마다 혹은 params마다 화면이 달라진다면? ⇒ 동적페이지!
- db를 이용하는 페이지라도 정적 페이지가 될 수 있음
- 정적 페이지라면 unstable_cache를 쓰지 않아도 캐쉬처럼 데이터가 갱신 x
- 갱신하려면 ? ⇒ revalidatePath 이용 or route segment config!
- fyi.
npm run build
로 프로덕션 빌드 시, 정적 페이지와 동적 페이지 구분을 확인할 수 있다.
정적→동적
- 정적 페이지 데이터 갱신 방법 in production ⇒ 원하는 페이지에 하단 코드 추가
- 방법1.
export const dynamic = ‘force-dynamic’
: 정적페이지를 동적페이지로 빌드 (항상 no cache) - unused_cache 사용해서 원하는 것만 캐쉬 적용할 수 있음
- 방법2.
export const revalidate = 60;
: 시간이 지났으면, 새 HTML 반환
동적→정적
generateStaticParams
동적 페이지(ex. /[id])를 prerender, 즉 static페이지로 만들고 싶다면?
⇒ 만들고 싶은 params 후보 객체 배열들을 return하는 generateStaticParams 코드 추가
export async const generateStaticParams() { return [ {id: "4"}, //id가 4or5면 정적페이지로 {id: "5"} ] } // 모든 디테일 페이지를 static 페이지로 만들기 export async const generateStaticParams() { const products = await prisma.product.findMany({}); return products.map(product=>({id: product.id+""})) }
fyi) 숫자+ "" 는 string으로 만듦
dynamicParams
미리 생성된 페이지만 볼 수 있게하는 옵션
export const dynamicParmas = true; //기본값 export const dynamicParmas = false;