[Next.js] Next.js 14 Caching 실전 압축 정리
Next.js에서의 CSR 구현
- Next.js의 cache 개념이 사용되지 않음 => 과거에 리액트에서 사용하는 방식과 완전히 동일
- 클라이언트 컴포넌트("use client")를 사용하고 useEffect 또는 React의 상태 관리를 활용
// app/members/page.js
'use client';
import { useState, useEffect } from 'react';
export default function MembersPage() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('https://api.example.com/members')
.then((res) => res.json())
.then((data) => setData(data));
}, []);
if (!data) {
return <p>Loading...</p>;
}
return (
<div>
<h1>Client-Side Rendering (CSR)</h1>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
Next.js의 cache
기본적으로 Next.js는 성능을 향상시키고 비용을 줄이기 위해 ‘가능한 한 많이 캐시’하는 전략을 사용
Request Memoization 부분은 React의 자체 기능으로 여기서는 생략
- Next.js에서의 캐시는 크게 클라이언트 캐시와 서버 캐시가 있음
- 클라이언트 캐시:
Router Cache
- 서버 캐시:
Full Route Cache
,Data Cache
- 클라이언트 캐시:
- 클라이언트와 서버 사이에는 "Build Time"이라는 개념이 존재
- 빌드 타임 동안에
'/a'
페이지에 대한 렌더링 수행 - 이때 필요한 데이터가 있다면, Data Source에서 데이터를 가져와 Data Cache에 저장
- Data Source는 일반적으로 프론트 서버이지만, 외부 데이터를 사용하는 경우 백엔드 서버일 수도 있음
- 데이터를 기반으로 렌더링을 수행한 결과를 Full Route Cache에 RSC payload와 HTML 형태로 저장
- 이후
'/a'
페이지에 대한 요청이 들어오면, Full Route Cache에 저장된 HTML과 RSC payload를 사용하여 페이지를 빠르게 렌더링함- 이는 데이터 요청이 한 번만 이루어지고, 이후에는 갱신되지 않음을 의미(장점이자 단점)
- 빌드 타임 동안에
Next.js에서의 SSG 구현
- Next.js는 기본 렌더링 방식으로 SSG를 채택함
- Next.js의 SSG는 기본적으로 모든 캐싱 매커니즘을 활용하여 성능을 극대화함
- SSG는 서버 캐시를 사용하는 기본적인 캐싱 방식임
- => SSG는 Full Route Cache를 사용하여 페이지를 정적으로 렌더링하는 방식
- 데이터의 변경이 거의 없거나 업데이트가 필요 없는 경우에 이상적이며, 성능을 극대화하는 데에 효과적
Dynamic segments에서의 SSG w. generateStaticParams
app/blog/[slug]/page.js
와 같이 dynamic segments를 사용하는 어떻게 SSG를 구현할 수 있을까? Next.js는 slug에 어떤 데이터가 올 수 있는지 알지 못한다. 때문에 기본적으로는 SSR을 활용하는 편이다.
하지만, generateStaticParams
을 사용하여 동적 세그먼트에 올 수 있는 데이터를 Next.js에게 알려줄 수 있다.
=> 이를 사용하면 generateStaticParams에서 제공하는 경로는 빌드 타임에 Full Route Cache에 캐싱된다
=> 즉, SSG를 제공할 수 있게 된다
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
Next.js에서의 SSR 구현
SSG는 빌드 타임에서 생성된 정적 페이지를 제공하지만, 최신 데이터를 반영하지 못한다.. 그리고 이를 Next.js에서는 기본값으로 사용한다.
그러나, 현실적인 프로젝트에서는 데이터가 업데이트될 때마다 최신 상태를 반영하는 동적 렌더링이 필요한 경우가 많다. 즉, 매 요청 시마다 서버에서 페이지를 렌더링하여 최신 데이터를 보장하는 SSR이 필요하다.
기본적인 SSG에서 SSR로 전환하려면 어떻게 해야할까?
SSG는 Full Route Cache를 이용하여 정적인 콘텐츠를 제공한다. Full Route Cache는 빌드 타임에 생성된 HTML과 데이터를 저장하며, 사용자가 페이지를 요청할 때마다 정적인 콘텐츠를 빠르게 제공할 수 있다.
위 이미지를 보자
- 정적 경로(Static Route)의 경우
- SSG를 통해 생성된 콘텐츠가 Full Route Cache에 저장되어 있음
- 이로 인해 사용자는 빌드 시점에 생성된 데이터를 항상 동일하게 받아볼 수 있음
- 동적 경로(Dynamic Route)를 사용하는 경우
- SSR을 의미
- Full Route Cache를 사용하지 않고, 매 요청마다 서버에서 페이지를 새로 렌더링
- SSR을 사용하려면 Full Route Cache를 스킵해야 함 (최신 데이터 반영을 위해)
=> SSR을 사용하려면 Full Route Cache를 무효화하거나 선택 해제해야 한다!
Full Route Cache의 무효화
- Revalidating Data Cache(= Data Cache를 재검증)
- Data Cache를 다시 검증(revalidate)하면 서버에서 구성 요소를 다시 렌더링하고 새로운 렌더 출력을 캐싱하여 Router Cache가 무효화됨
- Full Route Cache와 Data Cache는 모두 서버 캐시이며, 서로 밀접한 관계가 있다..
- Redeploying
- 배포 전반에 걸쳐 지속되는 데이터 캐시와 달리 전체 경로 캐신느 새 배포에서 지워짐
Full Route Cache와 Data Cache의 상호 관계
- Data Cache를 revalidate하거나 선택 해제(즉, 사용하지 않도록 설정)하면, Full Route Cache도 무효화됨
- => 데이터가 달라지면 그에 따라 렌더링 결과도 달라지기 때문
- => Data Cache가 무효화되면 Full Route Cache도 무효화되고, 최신 데이터를 사용하여 페이지를 렌더링할 수 있음
- 반대로, Full Route Cache를 무효화하거나 선택 해제해도, Data Cache는 영향 X
- = Full Route Cache가 없더라도 데이터는 여전히 캐시될 수 있음
- 이는 페이지의 대부분이 캐시된 데이터를 사용하더라도, 일부 구성 요소가 요청 시 가져올 새로운 데이터를 필요로 할 때 유용함
- 필요한 데이터만 동적으로 가져와 페이지를 렌더링할 수 있어, 모든 데이터를 다시 가져올 때의 성능 부담을 줄일 수 있음
- => 이는 Next.js가 하이브리드 캐싱을 지원하기 때문
Next.js 14의 하이브리드 캐싱
- Next.js 14는 기존의 페이지 단위 SSR과는 다른 접근 방식의 '하이브리드 캐싱'을 지원
- 서버 컴포넌트의 도입으로 각 API 요청에 대해 개별적으로 캐싱 여부를 결정할 수 있게 됨
- => 서버 컴포넌트와 클라이언트 컴포넌트가 함께 동작하며, 컴포넌트 단위로 세밀한 캐싱 제어가 가능
- 하이브리드 캐싱의 특징
- 컴포넌트 단위 캐싱: 서버 컴포넌트는 각 API 요청에 대해 개별적으로 데이터 캐싱 설정 가능
- => 페이지 단위가 아니라 컴포넌트 단위로 캐싱 가능
- Data Cache 우선순위: 특정 API 요청이 동적 데이터를 가져와야 하는 경우에도, 전체 페이지가 아닌 해당 컴포넌트의 데이터만 동적 렌더링 가능
- 하이브리드 데이터 접근: 컴포넌트는 필요에 따라 캐시된 데이터나 백엔드에서 실시간으로 가져온 데이터를 선택적으로 사용 가능. 이는 빠른 응답 시간과 최신 데이터 제공을 균형있게 유지하는 데에 유용함
- 컴포넌트 단위 캐싱: 서버 컴포넌트는 각 API 요청에 대해 개별적으로 데이터 캐싱 설정 가능
- React Suspense의 사전 부분 렌더링
- React Suspense를 사용하면 이러한 개별 캐싱 전략을 더 효과적으로 활용할 수 있음
- Suspense를 통해 컴포넌트가 준비될 때까지 대기하고, 필요한 데이터를 사전에 부분적으로 렌더링 가능
- => 사용자 경험을 향상 + 초기 로딩 시간 감소
Full Route Cache를 사용하지 않는 방법
특정 페이지나 레이아웃에서 Full Route Cache 자체를 사용하지 않도록 하여 모든 요청에 대해 동적으로 렌더링하도록 할 수 있음.
=> 즉, SSG 기능 사용하지 않는다는 의미
- Dynamic API 사용
cookies
나headers
와 같은 동적 API와 체이지의searchParams
prop은 런타임에 들어오는 요청 정보에 따라 달라짐- 이들을 사용하면 Full Route Cache를 사용하지 않게 된다 => 즉, 모든 경로가 동적으로 렌더링됨
cookies
- 서버 액션에서
cookies.set
이나cookies.delete
사용하면, Router Cache가 무효화되어 쿠키를 사용하는 경로가 오래되는 것을 방지할 수 있다(ex. authentication 변경 사항 반영을 위해)
- 서버 액션에서
- Route Segment Config 옵션 중
dynamic = 'force-dynamic'
또는revalidate = 0
사용- 이들을 사용하면 Full Route Cache와 Data Cache를 스킵
- 즉, 서버로 들어오는 모든 요청에 대해 서버 캐시를 사용하지 않고 동적으로 응답하는 것
- 단, 클라이언트 캐시인 Route Cache는 여전히 사용
- 반드시 동적으로만 렌더링해야 하는 페이지나 레이아웃의 경우, 명시적으로 이 route segment config를 사용하면 됨
- 하지만, 이 방식은 실제로 동작하지 않는 경우가 많음!!! -> 바로 다음 Data Cache에 대해 알아보며 그 이유를 알아보자
- Data Cache를 사용하지 않기
- 경로에 캐시되지 않은 fetch 요청이 있는 경우, Full Route Cache를 사용하지 않게 된다
- 특정 fetch 요청에 대한 데이터는 들어오는 모든 요청에 대해 fetch 된다.
- 캐싱을 사용하지 않는 다른 fetch 요청은 여전히 데이터 캐시에 캐싱된다. 이를 통해 캐시된 데이터와 캐시되지 않은 데이터를 모두 사용할 수 있다.
데이터 캐시 로깅
14.1 버전부터 데이터 캐시를 로깅할 수 있는 기능이 추가됨
이제 캐시가 있었는지 HIT 또는 SKIP 요청된 전체 URL이 있는지 표시 가능module.exports = { logging: { fetches: { fullUrl: true, } } };
dynamic = 'force-dynamic'
또는 revalidate = 0
이 동작하지 않는 이유
Next.js 14에서는 기본적으로 SSG(Static Site Generation) 방식을 채택하고 있으며, 이로 인해 Data Cache의 기본 설정은 force-
cache
임
=> fetch 요청 시 옵션값으로 {cache: 'force-cache'}
를 굳이 넘겨주지 않아도 기본적으로 force-cache가 적용됨
=> 즉, fetch 요청의 기본값은 캐시를 사용하도록 설정됨
이로 인해, dynamic = 'force-dynamic'
또는 revalidate = 0
를 사용하여도 데이터 캐시와 풀라우트 캐시가 무효화되지 않는 경우가 발생하게 됨.. Data Cache의 기본 설정이 캐시를 사용하도록 설정되어 있기 때문..
=> 앞서 본 것처럼 Data Cache에 우선 순위가 있음
또한, 경로에 여러 API 요청 중 하나라도 동적 렌더링을 수행한다면? => 해당 경로의 Full Route Cache가 이미 무효화됨
=> dynamic = 'force-dynamic'
또는 revalidate = 0
를 사용하지 않아도 경로의 일부가 동적으로 렌더링되면 Full Route Cache가 무효화됨
=> dynamic = 'force-dynamic'
또는 revalidate = 0
를 사용하는 것은 경로 내의 모든 서버 캐시를 무효화한다는 것을 '명시적으로 표시'하기 위한 방법임
Next.js 팀도 이러한 문제를 인식하여, Next.js 15부터는 fetch 요청의 기본 캐시 속성을 force-cache에서 no-store로 변경함
이는 fetch 요청이 기본적으로 캐시되지 않음을 의미
Data Cache의 선택 해제
각각의 API의 Data Cache를 선택해제 하려면 fetch 요청 시 cache 속성을 'no-store'로 설정혀만 됨
const res = await fetch('https://api.vercel.app/blog', { cache: 'no-store' })
이렇게 하면 해당 요청에 대해 Data Cache가 사용되지 않고, 매번 새로운 데이터를 가져오게 됨
이처럼 Data Cache를 선택해제 하면 Full Route Cache도 무효화됨. Data Cache와 Full Route Cache는 모두 서버 캐시로 분류됨.
서버 캐시의 무효화를 통해 우리는 동적으로 데이터를 fetching하고 SSR을 구현할 수 있음
Next.js에서의 SSR 구현 방법 정리
- Data Cache 선택 해제(= Full Route Cache의 무효화)
- => 특정 fetch 요청에 대해
cache: 'no-store'
를 설정하여 Data Cache를 사용하지 않도록 함 - Data Cache를 무효화하면, Full Route Cache도 함께 무효화
- => 특정 fetch 요청에 대해
// app/members/[id]/page.js
export default async function MemberPage({ params }) {
const data = await fetch(`https://api.example.com/members/${params.id}`, {
cache: 'no-store', // SSR을 위해 캐싱 비활성화
}).then((res) => res.json());
return (
<div>
<h1>Server-Side Rendering (SSR)</h1>
<h2>Member {params.id}</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
- Dynamic API 사용
Next.js 에서의 ISR 구현
지금까지 SSG와 SSR을 사용하는 방법에 대해 알아보았다.
그렇다면 ISR은 어떻게 사용할 수 있을까?
ISR은 SSG를 기반으로 하되, 특정 조건에 따라 새로운 데이터를 가져와 페이지를 업데이트 할 수 있도록 한다.
기본적으로 캐시된 데이터를 사용하지만, 데이터의 최신화가 필요한 경우 데이터 캐시를 무효화하여 SSR 방식으로 페이지를 동적으로 렌더링할 수 있다. 이를 '데이터 재검증'이라고 한다.
캐시된 데이터의 2가지 재검증 방법
- Time-based Revalidation: 일정 시간이 지난 후 새로운 요청이 발생한 후 데이터를 재검증
- 자주 변경되지 않고 최신성이 중요하지 않은 데이터에 유용
- On-demand Revalidation: 이벤트 기반으로 데이터를 재검증
- 태그 기반 또는 경로 기반 접근 방식을 사용하여 데이터 그룹을 한 번에 재검증 가능
- 가능한 한 빨리 최신 데이터를 표시하려는 경우에 유용함
Time-based Revalidation
Next.js에서는 일정 시간 간격으로 데이터를 재검증하여 최신 상태를 유지할 수 있음
=> fetch 요청에서 리소스의 캐시 수명을 초 단위로 설정할 수 있는 next.revalidate
옵션을 사용
// 최대 1시간마다 데이터 검증
fetch('https://...', { next: { revalidate: 3600 } })
- 처음 요청 시 외부 데이터 소스에서 데이터를 가져와 데이터 캐시에 저장
- 지정된 기간(ex. 60초) 내에 호출되는 모든 요청은 캐시된 데이텉를 반환
- 해당 기간이 지난 후에도 다음 요청은 여전히 캐시된 데이터를 반환
- Next.js는 백그라운드에서 데이터 재검증을 실행함
- 데이터를 성공적으로 가져오면 Next.js는 데이터 캐시를 새로운 데이터로 업데이트
- 백그라운드 재검증이 실패하면 이전 데이터는 변경되지 않은 상태로 유지
주의: cache: 'no-store'와 revalidate 옵션을 함께 사용하면 충돌이 발생하고, 이러한 충돌은 정확한 데이터 제공을 방해할 수 있다
On-demand Revalidation
필요에 따라 경로(revalidatePath) 또는 캐시 태그(revalidateTag)를 통해 데이터의 유효성을 다시 검사할 수 있음
- 요청이 처음 fetch 호출되면 외부 데이터 소스에서 데이터를 가져와 데이터 캐시에 저장됨
- 요청 시 유효성 재검사가 트리거되면 해당 캐시 항목이 캐시에서 제거(
PURGE
)됨- 이는 새로운 데이터를 가져올 때까지 오래된 데이터를 캐시에 보관하는 Time-based Revalidation과는 다름
- 다음에 요청이 이루어지면 다시 캐시가 되며
MISS
데이터는 외부 데이터 소스에서 가져와 데이터 캐시에 저장
On-demand Revalidation - revalidateTag
- Next.js에서는 특정 데이터 항목을 태그로 구분하여 캐시를 관리할 수 있음
revalidateTag
기능을 사용하면 지정된 태그와 관련된 캐시 항목을 재검증하거나 무효화할 수 있음- 이 방법은 특정 조건이나 이벤트가 발생했을 때 해당 데이터만 재검증하고 싶을 때 유용
// 태그를 통해 Data Cache 설정
fetch(`https://...`, { next: { tags: ['a', 'b', 'c'] } })
// 특정 태그와 관련된 항목을 재검증합니다.
revalidateTag('a');
revalidateTag
를 사용하는 위치에 따라 2가지 방법이 있음- Route Handlers
- Route Handlers를 사용하여, 웹훅과 같은 외부 이벤트에 응답하여 데이터를 재검증 가능
- Route Handlers는 특정 경로에 연결되지 않으므로, 이 방법으로는 Router Cache가 즉시 무효화되지는 않음
- Server Actions
- 양식 제출과 같은 사용자 작업 후 데이터 재검증 가능
- Server Actions를 통해 데이터를 재검증하면 해당 경로에 대한 Router Cache도 무효화됨
- Route Handlers
On-demand Revalidation - revalidatePath
- revalidatePath는 특정 경로의 데이터를 수동으로 재검증하고 해당 경로 아래의 경로 세그먼트를 다시 렌더링할 수 있음
- 이 메서드를 호출하면 경로에 있는 모든 Data Cache가 무효화되고, 결과적으로 Full Route Cache도 무효화
- => 최신 데이터를 사용하여 경로를 다시 렌더링 가능
// 루트 경로('/')의 데이터를 재검증합니다.
revalidatePath('/');
revalidatePath
도revalidateTag
와 마찬가지로 Route Handlers와 Server Actions에서 사용 가능
Next.js에서의 ISR 구현 정리
- Time-based Revalidation -> fetch 요청에 next.revalidate 옵션을 사용하여 리소스의 캐시 수명 설정
- On-demand Revalidation -> revalidateTag 또는 reavlidatePath 함수를 사용
revalidateTag와 revalidatePath를 사용하면 서버 캐시뿐만 아니라, 클라이언트 캐시인 Router Cache도 재검증 가능 => 클라이언트 측에서 캐시된 데이터의 유효성을 검사하여, 항상 최신 상태의 데이터를 보여주기 위해 사용
// app/members/[id]/page.js
export default async function MemberPage({ params }) {
const data = await fetch(`https://api.example.com/members/${params.id}`, {
next: { revalidate: 60 }, // 60초마다 정적 페이지 재생성
}).then((res) => res.json());
return (
<div>
<h1>Incremental Static Regeneration (ISR)</h1>
<h2>Member {params.id}</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
Router Cache(클라이언트 캐시) 관리
위의 이미지는 Next.js 14의 기본 캐시 전략을 시각적으로 설명하고 있다.
이 이미지에서 알 수 있듯이, Next.js는 첫 방문 시 서버 캐시(풀 라우트 캐시 및 데이터 캐시)를 사용하지만, 이후의 모든 재방문 시에는 클라이언트 측 라우터 캐시에서 페이지를 로드한다.
이로 인해 서버사이드에서 렌더링 하는것이 정적이던 동적이던 우리는 클라이언트의 라우터 캐시에 저장된 RSC 페이로드 결과 통해 페이지를 보게 된다.
Router Cache
- Next.js는 사용자가 경로 사이를 탐색할 때 방문한 경로 세그먼트를 클라이언트 측 라우터 캐시에 저장하고, 사용자가 탐색할 가능성이 있는 경로를 미리 가져옴(pre-fetching)
- 이러한 캐싱과 pre-fetching 매커니즘 덕분에 사용자는 더욱 원활하고 빠른 탐색 경험 가능
- 즉각적인 뒤로가기/앞으로가기: 이미 방문했던 경로들은 라우터 캐시에 저장되어 있기 때문
- 빠른 새 경로 탐색: 경로 세그먼트가 미리 가져와지면, 새 경로로의 탐색이 훨씬 빠르게 이루어짐
- 이는 특히 Partial Rendering과 결합되어, 페이지의 특정 부분만 업데이트 되어도 전체 페이지를 다시 로드할 필요 X
- 상태 유지: 탐색 중에도 전체 페이지를 다시 로드 X -> React 상태와 브라우저 상태가 유지
Router Cache vs. Full Route Cache
- Router Cache
- 사용자 세션 동안 브라우저에 React 서버 구성 요소 페이로드를 임시로 저장
- 정적 및 동적으로 렌더링된 경로 모두 캐시
- Full Route Cache
- 여러 사용자 요청에 걸쳐 서버에 React 서버 구성 요소 페이로드와 HTML을 지속적으로 저장
- 정적으로 렌더링된 경로만 캐시
Router Cache의 문제점
- Router Cache는 유효 기간을 가진다.
- 기본적으로 설정된 시간 동안 캐시가 유지되며, 이 기간이 지나면 자동으로 무효화됨
- 하지만, 14.1 버전에서 Router Cache를 완전히 비활성화 하는 방법은 X => 몇가지 문제 발생
- 특정 경로에 대한 첫 방문 후 해당 페이지의 데이터가 업데이트 된 경우
- 이후 페이지 다시 방문하면, 서버 캐시를 재검증하거나 무효화하여 SSR 또는 ISR을 사용하더라도 업데이트된 데이터를 보지 못할 수 있음..!
- (Router Cache는 재검증되지 않았기 때문..)
- 이 문제에 대해 많은 이슈를 제기해왔고, 이에 따라 Next.js 팀은 라우터 캐시의 유효 기간을 조절할 수 있는 실험적 기능을 14.2 버전에 도입
- 더 나아가, Next.js 15 버전에서는 라우터 캐시가 기본적으로 캐시되지 않음
- => 사용자가 원하는 경우에만 라우터 캐시 사용 가능 + 캐시의 지속 시간 직접 설정 가능
Router Cache의 유효 기간
- Router Cache는 브라우저의 임시 메모리에 저장되며, 유효 기간은 Prefetch된 방식에 따라 다름
- Prefetch: 기본적으로 구성 요소는 자동으로 Full Route Cache에서 경로를 미리 가져오고, RSC 페이로드를 Router Cache에 추가함
- Router Cache는 prefetch의 영향을 받기 때문에 Prefetch Cache라고 불리기도 함
- prefetch는
Link
태그를 대상으로 하며, 그 방식은prefetch
속성으로 명시 가능router.prefetch()
함수도 있음
- Router Cache의 유효 기간은 다음 2가지 요인에 따라 결정
- Session: 캐시는 탐색 중에 지속됨. 그러나, 페이지 새로 고침 시 지워짐
- Automatic Invalidation Period: 레이아웃 및 로딩 상태 캐시는 특정 시간 이후에 자동으로 무효화됨
- 이 시간은 리소스가 pre-fetch된 방식과 리소스가 정적으로 생성되었는지 여부에 따라 다름
- Default Prefetching(
prefetch={null}
or unspecified): 동적 페이지에는 캐시되지 않고, 정적 페이지는 5분 - Full Prefetching(
prefetch={true}
orrouter.prefetch
): 동적 & 정적 페이지 모두 5분
- Default Prefetching(
- 이 시간은 리소스가 pre-fetch된 방식과 리소스가 정적으로 생성되었는지 여부에 따라 다름
- 페이지 새로 고침 시 캐시된 세그먼트가 모두 지워지지만, Automatic Invalidation Period는 미리 가져온 시간 이후의 개별 세그먼트에만 영향을 미침
Prefetch
사용자가 Link 태그에 마우스를 올리거나, 해당 Link 태그가 뷰포트에 들어왔다면 프리페칭을 수행함
=> 방문할 가능성이 있는 경로의 정보 및 데이터를 미리 가져와 첫 방문 시의 지연을 없앰
prefetch={null}
또는 unspecified (기본값)- 정적 경로의 경우 => 전체 경로와 모든 데이터를 프리페치하고 Router Cache에 저장
- 동적 경로의 경우 => loading.js 경계가 있는 가장 가까운 세그먼트까지 부분적으로 프리페치하고 Router Cache에 저장
product/[id]
경로에 대한 프리페치는 실제 데이터 요청을 하지 않고, 이 경로에 포함된 가장 가까운 loading.js 경계를 찾아, 이 세그먼트까지의 데이터를 미리 가져옴.- 예를 들어,
app/product/[id]/loading.js
파일이 있으면, Next.js는 이 로딩 파일을 먼저 프리페치 - 그러나,
/product/[id]
경로의 구체저긴 데이터(ex. product의 상세 정보)는 프리페치하지 않고, 사용자 요청 시에 로드 - => 즉, 동적 데이터는 프리페치 시점이 아닌 방문 시점에야 Router Cache에 저장 (과도한 데이터 페칭을 방지하기 위함)
- 이 프리페치된 데이터는 30초 동안 유효 (라우터캐시에 저장)
prefetch={true}
- 정적 및 동적 경로 모두에 대해 전체 경로와 데이터를 프리페치하고 라우터 캐시에 저장
- 이 프리페치된 데이터는 5분 동안 유효 (라우터캐시에 저장)
- 이는 사용자가 해당 경로로 이동할 때 빠르게 페이지를 렌더링할 수 있게 함
- 단점: 네트워크 사용량, 서버 부하, 메모리 사용, 그리고 최신 데이터 유지의 어려움 등 여러 가지 단점을 동반할 수 있음
- 이를 줄이기 위해 상황에 맞게 프리페칭을 적절히 조절하는 것이 중요
prefetch={false}
- 프리페치를 비활성화 (!= Router Cache 비활성화)
- 하지만 프리페치 기능을 비활성화해도 여전히 Router Cache는 30초 동안 유효
- => 사용자가 페이지를 방문하면 방문한 페이지의 데이터는 라우터 캐시에 저장됨
- => 첫 방문 시에만 지연
Router Cache의 무효화 방법
Next.js 14.1 버전까지는 Router Cache를 완전히 사용하지 않는 방법은 없음
그러나, Router Cache를 무효화하는 방법은 있음. 이를 통해 유효 기간이 남은 Router Cache를 무효화하고 최신 데이터를 반영하도록 할 수 있음
router.refresh
- 클라이언트 컴포넌트에서 사용 가능한 메서드
- 현재 페이지를 새로고침하여 라우터 캐시를 무효화하고, 서버로부터 새로운 데이터를 받아옴
- 이 방법은 Router Cache만을 무효화하고, 서버 캐시는 여전히 유효할 수 있음
revalidatePath
- Server Action이나 Route Handlers에서 사용 가능한 메서드
- 특정 경로의 캐시를 무효화하여 해당 경로의 Router Cache와 Data Cache를 모두 무효화
- 이를 통해 클라이언트 측 캐시와 서버 측 캐시를 모두 지워 최신 데이터 조회 가능
revalidateTag
- Server Action이나 Route Handlers에서 사용 가능한 메서드
- 특정 태그와 연관된 캐시 항목을 무효화하여, 해당 데이터가 최산 상태가 되도록 함
- 이 역시 Router Cache와 Data Cache를 모두 무효화하여 클라이언트 및 서버 모두에서 최신 데이터 보장
Next.js 15의 캐싱 관련 변경점
- 기본적으로 fetch 요청이 더 이상 캐시되지 않음 (
'no-store'
가 기본이 됨)- 캐시 사용 방법
- fetch 사용 시
'force-cache'
로 설정 - 단일 라우트에 대해 dynamic 라우트 구성 옵션을
'force-static'
으로 설정 - fetchCache 라우트 구성 옵션을
'default-cache'
로 설정하여 Layout 또는 Page에서 모든 fetch 요청이 force-cache를 사용하도록 설정 가능
- fetch 사용 시
- 캐시 사용 방법
- 클라이언트 Router Cache는 더 이상 기본적으로 페이지 구성 요소를 캐시하지 않음
참고 자료