캐시 전략
Next.js 공식문서의 caching 부분을 읽고 정리해봤다.
https://nextjs.org/docs/app/building-your-application/caching
Request Memoization
- 컴포넌트 렌더링 중
fetch
요청의 결과 값을 캐싱, GET method만 허용 - 렌더링 중에만 유지
- 컴포넌트 트리에서 같은
fetch
여러 번 해도 실제로는 여러 번 요청 안하고 캐싱된 값을 사용 - 리액트의 기능임
Data Cache
- fetch 요청의 결과 값을 캐싱, 서버에서 들고 있고 여러 사용자의 동일한 요청에 대응하기 위함
- Next.js가
fetch
기능 확장해서 써서 가능한 기능 - revalidate, opt out 하기 전까지 계속 유지
- Revalidating
- 시간 기반으로 Revalidation
// Revalidate at most every hour fetch('https://...', { next: { revalidate: 3600 } })
- on-demand Revalidation
revalidatePath
나revalidateTag
로 명시적으로 요청
- Opting out
let data = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })
Full Route Cache
- 빌드타임에 route들 캐싱
- 동작 단계
- 서버에서 리액트 렌더링
- 리액트는 서버 컴포넌트를 스트리밍에 용이한 React Server Component Payload로 렌더
- Next.js는 React Server Component Payload 와 Client Component 사용하여 HTML 렌더
- 서버에서 Next.js 캐싱
- Next.js는 라우트별로 RSCP와 HTML을 캐싱 - static하게 렌더된 route들에만 적용
- 리액트 Client 단에서 Hydration 과 Reconciliation
- HTML은 로딩시 빠르게 첫 화면을 보여줌
- RSCP는 Client단에서 Reconcil하고 서버 컴포넌트 트리 렌더, DOM을 갱신
- javascript 파일들이 client 컴포넌트들 hydrate
- Client 단에서 Next.js 캐싱
- RSCP는 client 단에서 라우트 별로 캐싱됨 (Router Cache)
- Router Cache는 메뉴 이동시 사용자 경험 향상 - 나중에 이동할 route들 prefetch함
- Subsequent Navigations
- 연속 라우트 이동, 라우트 prefetch시 Next.js는 Router Cache를 먼저 확인
- 서버에서 리액트 렌더링
- Static, Dynamic rendering
- Static route들은 기본적으로 캐싱
- dynamic route들은 캐싱 안하고, request 시 렌더
- Duration
- 기본적으로 영구적임
- Invalidation
- Revalidating Data https://nextjs.org/docs/app/building-your-application/caching#revalidating
- Redeploying: 새 배포시 초기화 - Data Cache는 배포간에도 유지된다???
- Opting out
- dynamic 하게 route 만들면 됨
- dynamic api 사용
- route segment config에
dynamic = ‘force-dynamic’
|revalidate = 0
- data cache opt out: fetch가 cache되지 않도록 설정
- dynamic 하게 route 만들면 됨
Client-side Router Cache
인메모리로 route별 cache 저장
사용자가 route돌아다니면 방문한 route segements들 캐싱, 유저가 방문할 라우트 prefetch
덕분에 빠르게 앞, 뒤로 가기 | 라우트 이동 시 전체 새로고침 X | 브라우저, 리액트 상태 보존
- layout 캐시하여 라우트 이동시 사용 - partial rendering
- loading states 캐시하여 라우트 이동시 사용
- Pages는 기본적으로 캐싱하지 않음 하지만 앞, 뒤로가기 시 재사용
- page segments들은 experimental ‘staleTimes’ 사용하여 캐싱 설정 가능
- Duration
- 브라우저 메모리에 저장
- 라우트 이동 간 저장 새로고침시 날아감
- Automatic Inavalidation Period
- Default Prefetching(
prefetch={nulll}
): dynamic 페이지는 캐시 x static 페이지는 5분 - Full Prefetching(
prefetch={true}
orrouter.prefetch
): dynamic, static 둘 다 5분
- Default Prefetching(
- Invalidation
- Server Action에서
revalidatepath
orrevalidateTag
cookies.set
orcookies.delete
- 쿠키 쓰는 페이지는 캐시 무효화
- router.refresh 는 라우터 캐시 invalidate, 서버에 요청
- Server Action에서
- Opting out
- Next.js 15버전에서 페이지 segements들은 라우터 캐시가 적용되지 않음
Cache Interactions
- Data Cache와 Full Route Cache
- Data Cache opt out하거나 revalidate 하면 Full Route Cache도 invalidate - 데이터에 따라 렌더 되기 때문
- Full Route Cache Invalidate하거나 opt out해도 Data Cache에는 영향 X, data가 캐시되든 안되든 dynamic하게 라우트 렌더 가능 - 특정 컴포넌트만 캐시 안된 데이터 쓸 경우 유용하다. 전체 data fetch 안하고 필요한 data만 fetch함
- Data Cache와 Client-side Router cache
- Server action에서
revalidatePath
,revalidateTag
로 Data Cache와 Router cache invalidate 가능 - Route Handler에서 Data Cache invalidate시 즉각적으로 Router Cache에 영향 주지 않음 - Router Handler가 특정 라우트와 묶여 있지 않기 때문, Router Cache는 만료되기 전, 강력 새로고침 전까지 이전 payload를 제공함
- Server action에서
APIs
API | Router Cache | Full Route Cache | Data Cache | React Cache |
---|---|---|---|---|
<Link prefetch> |
Cache | |||
router.prefetch |
Cache | |||
router.refresh |
Revalidate | |||
fetch |
Cache | Cache | ||
fetch options.cache |
Cache or Opt out | |||
fetch options.next.revalidate |
Revalidate | Revalidate | ||
fetch options.next.tags |
Cache | Cache | ||
revalidateTag |
Revalidate (Server Action) | Revalidate | Revalidate | |
revalidatePath |
Revalidate (Server Action) | Revalidate | Revalidate | |
const revalidate |
Revalidate or Opt out | Revalidate or Opt out | ||
const dynamic |
Cache or Opt out | Cache or Opt out | ||
cookies |
Revalidate (Server Action) | Opt out | ||
headers , searchParams |
Opt out | |||
generateStaticParams |
Cache | |||
React.cache |
Cache | |||
unstable_cache |
Cache |
<Link>
default로 <Link>
컴포넌트는 Full Route Cahce로부터 route들을 prefetch, RSCP를 Router Cache에 넣어 둠
prefetch 비활성화하려면 prefetch={false}
, 이렇게 해도 사용자가 route 방문시에 캐싱은 계속 함
router.prefetch
라우트 수동으로 prefetch
router.refresh
클라이언트 라우트 캐시 clear, 서버에 새 요청 | 하지만 Data와 Full Route Cache에는 영향 안줌
react, 브라우저 상태 유지하면서 화면 변경됨
fetch
fetch
응답은 자동으로 Data Cache에 캐시되지 않음
default는 {cache: ‘no-store’}
fetch options.cache
fetch별로 캐시 강제할 수 있음 {cache: ‘force-cache’}
fetch options.next.revalidate
revalidate 주기 설정 가능, Data Cache revalidate하고 그에 따라 Full Route Cache도 revalidate됨
서버에서 컴포넌트 재렌더 {next: {revalidate: 3600} }
fetch options.next.tags 와 revalidateTag
Next.js에는 캐시 태깅 시스템이 있음
fetch 시에 캐시에 태깅 가능
revalidateTag
로 태그에 묶인 캐시들 revalidate
// Cache data with a tag
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })
// Revalidate entries with a specific tag
revalidateTag('a')
Route Hadnler와 Server Action에서 revalidateTag
사용 가능
revalidatePath
data revalidate하고 route segement 리렌더
Data Cache revalidate 하고 Full Route Cache revalidate 함
Route Hadnler와 Server Action에서 revalidatePath
사용 가능
Dynamic APIs
cookies
, headers
, searchParams
는 런타임 요청 정보 등에 의존적
얘네를 쓰면 Full Route Cache opt out 된다 - 다이나믹 렌더
cookies
cookies.set
or cookies.delete
서버액션에서 쓰면 Router Cache invalidate
Segement Config options
route segement default 오버라이딩 가능, fetch API 못쓸때 사용할 수 있음
const dynamic = ‘force-dynamic’
- Full Route Cache opt outconst fetchCache = ‘default-no-store’
모든 fetch Data Cache opt out
generateStaticParams
dynamic segments를 쓸 때 generateStaticParams
에 넘겨진 path 들은 빌드 타임에 Full Route Cache에 캐시됨
request시 Next.js는 path 들 캐싱함
static하게 모든 paths들을 빌드 타임에 캐시하려면, generateStaticParams
에 모든 path들을 넘기면 됨
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
일부만 빌드타임에 캐시하려면, 일부만 넘기면 됨
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
// Render the first 10 posts at build time
return posts.slice(0, 10).map((post) => ({
slug: post.slug,
}))
}
첫 방문시에 빌드하도록 - 빌드타임에 렌더안하도록 하려면
export const dynamic = 'force-static'
또는 generateStaticParams
에 빈 배열 넘기면 됨
export async function generateStaticParams() {
return []
}
slug쓰는 경우 위에 generateStaticParams
설정 안해놓으면 dynamic 렌더 | 빈 배열 넘기면 static 렌더함
request시 캐싱 비활성화 하려면
export const dynamicParams = false
이거 주면 generateStaticParams
에 넘긴 path들만 서빙됨 | 그 외 path들은 404 또는 catch-all routes로 감
React cache function
함수 리턴 값 메모이제이션 가능
fetch
는 자동으로 메모이제이션 됨
fetch
못 쓸 경우에 얘 써서 메모이제이션 하자
import { cache } from 'react'
import db from '@/lib/db'
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id })
return item
})
'프론트엔드 > Next.js' 카테고리의 다른 글
Next.js 14 App router에 Auth.js v5 적용 후기 (0) | 2024.08.25 |
---|---|
데이터 목록 ui 공통 컴포넌트, 훅으로 관리하기 (0) | 2024.05.19 |
Next.js 14 기초 활용법 (1) | 2024.02.24 |