기존 Pages Router에서는 클라이언트 컴포넌트로만 이루어져 있었다. 이때, 클라이언트 컴포넌트에 async 키워드를 사용하면 브라우저의 동작에 문제를 일으킬 수 있기 때문에 해당 키워드를 사용하는 것은 권장되지 않는다. 따라서 컴포넌트 내에서 비동기적으로 데이터를 불러오는 것은 불가능했으며, 해당 동작을 수행하려면 서버에서만 실행되는 getServerSideProps 등의 특수한 함수를 사용해야 했다. 하지만 이런 동작은 자식 컴포넌트에서 데이터를 사용하기 위해 부모에서 데이터를 페칭하고 계속해서 props를 내려주거나 Context API를 사용해야 했다.
반면, App Router에서는 서버 컴포넌트를 활용함으로써 async 키워드와 함께 컴포넌트에서 데이터 페칭을 수행할 수 있게 되었다. 따라서 데이터가 필요한 컴포넌트에서 개별적으로 데이터 페칭을 수행하면 된다.
fetch 메서드를 활용해 불러온 데이터를 Next 서버에서 보관하는 기능으로, 데이터를 영구적으로 보관하거나, 특정 시간을 주기로 갱신하는 것도 가능하다. 이를 통해 불필요한 데이터 요청 수를 줄여 웹 서비스의 성능을 크게 개선할 수 있다.
이 기능은 fetch를 확장한 것으로, axios 등의 외부 라이브러리에는 적용할 수 없다.
Next.js에서는 데이터 페칭 시 서버에 로그를 찍어주는 기능을 제공한다.
next.config.mjsconst nextConfig: NextConfig = { /* config options here */ logging: { fetches: { fullUrl: true, }, }, }
no-store데이터 페칭의 결과를 저장하지 않으며, 캐싱을 전혀 수행하지 않는다. fetch에 아무런 캐싱 옵션을 지정하지 않는 경우와 동일한 동작을 한다.
async function AllMovies() {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_SERVER_URL}/movie`,
{ cache: "no-store" }
);
}
async function RecoMovies() {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_SERVER_URL}/movie/random`
);
}
force-cache요청의 결과를 무조건 캐싱한다. 한 번 호출된 이후에는 다시는 호출되지 않는다.
async function RecommendMovies() {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/movie/random`,
{
cache: "force-cache",
}
);
}
{next: { revalidate: x }}특정 시간을 주기로 캐시를 업데이트한다. Pages Router의 ISR 방식과 유사하다.
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/movie/random`,
{
next: { revalidate: 3 },
}
);
{ next: { tags: ['a'] } }요청이 들어왔을 때 데이터를 최신화하며, Pages Router의 on-demand revalidate 방식과 유사하다.
| 옵션명 | 설명 |
|---|---|
| "no-store" (default, Next v15 이상) | 데이터 페칭의 결과를 저장하지 않으며, 캐싱을 전혀 수행하지 않는다. |
| "force-cache" | 요청의 결과를 무조건 캐싱하며, 한번 호출된 이후에는 다시 호출되지 않는다. |
| { next: { revalidate: x(초) } } | 특정 시간을 주기로 캐시를 업데이트하며, page router의 ISR 방식과 유사하다. |
| { next: { tags: ['a'] } } | 요청이 들어왔을 때 데이터를 최신화하며, page router의 on-demand revalidate 방식과 유사하다. |
하나의 페이지를 렌더링하는 동안에 중복된 API 요청을 캐싱하기 위해 존재하는 개념이다. App Router에서는 서버 컴포넌트의 도입으로 서로 다른 컴포넌트가 서로 같은 데이터를 필요로 하는 상황에서 중복된 데이터 페칭이 필연적으로 수행된다.
리퀘스트 메모이제이션은 같은 페이지를 렌더링하는 과정에서 여러 컴포넌트가 동일한 fetch 요청을 할 때, 실제 요청은 한 번만 수행하고 결과를 공유하게 해준다. 이를 통해 동일한 API 요청이 한 번의 서버 렌더링 주기 내에서 중복되는 것을 방지한다.
| Request Memoization | Data Cache | |
|---|---|---|
| 보존기간 | 렌더링 종료 시 소멸 | 서버 가동중에는 영구 보관 |
| 목적 | 하나의 페이지를 렌더링하는 동안 중복된 API 요청 보관 | 백엔드 서버로부터 불러온 데이터 보관 |
데이터 캐시는 서버 다운 전까지 지속되지만, 리퀘스트 메모이제이션은 한 번의 서버 렌더링 주기 후에 초기화된다.
참고자료
한 입 크기로 잘라먹는 Next.js (이정환)