Next.js에서는 Cache가 정말 중요하다 생각될 정도로 모든 데이터를 캐싱해버린다.
이 이미지는 Next.js의 공식 홈페이지에서 자신들이 어떻게 캐시를 관리하는지 보여주는 이미지이다. 이미지상에서만 캐시의 종류가 4개가 존재한다. 하나씩 캐시가 어떻게 동작하는지 알아보자.
❗RSC라는 단어가 조금씩 나오는데 RSC는 React Server Component의 약자이다.
Next.js는 빌드 시점에 페이지를 렌더링 하고 그 결과를 캐싱하는 Full Route Cache 기능을 제공한다.
이 캐시를 이용하여 서버는 매 요청마다 페이지를 다시 렌더링 하지 않고, 미리 생성된 HTML과 데이터를 빠르게 제공할 수 있어 페이지 로딩 속도가 크게 향상된다.
이 과정에서 Next.js는 서버에서 React의 API를 활용해서 렌더링을 진행한다.
기본적으로 Full Route Cache는 지속적이며, 사용자 요청 간에 렌더링 결과가 캐싱되어 있다. 그래서 동일한 페이지에 대한 요청이 있을 때마다 서버는 빠르게 응답하여 페이지를 보여준다.
그러나 데이터가 변경되거나, 실시간 정보가 필요한 페이지의 경우에는 이 캐시를 무효화하거나 동적 렌더링을 할 수 있다. revalidate
옵션 등의 기능을 통해 제어가능하다.
Next.js의 Data Cache는 fetch
함수를 기반으로 데이터를 캐싱하여, 서버 요청 간에도 데이터를 지속적으로 활용할 수 있게 해준다. 이는 외부 데이터 소스에 대한 요청 수를 줄이고, 응답 시간을 개선하는 데 큰 도움을 준다.
Next.js의 fetch
는 브라우저의 fetch
API를 확장한 것으로, 서버 측에서 각 요청에 맞는 캐싱 전략을 설정할 수 있다. 기본적으로 fetch
함수를 사용하면 데이터가 자동으로 캐싱되며, 이는 동일한 데이터에 대한 중복 요청을 방지한다. 이는 후술에서 Request Memoization에서 볼 수 있다.
예를 들어, 다음과 같이 fetch
를 사용할 수 있다:
const res = await fetch('<https://api.example.com/data>', { next: { revalidate: 3600 } });
const data = await res.json();
위 코드에서 { next: { revalidate: 3600 } }
옵션은 해당 데이터가 캐시에 저장된 후 3600초(1시간) 동안은 재검증 없이 캐시된 데이터를 사용하도록 설정한다. ISR의 방식으로 볼 수 있다.
만약 특정 데이터를 캐싱하지 않고 매번 최신 데이터를 가져오고 싶다면, 다음과 같이 옵션을 설정할 수 있다:
const res = await fetch('<https://api.example.com/data>', { cache: 'no-store' });
const data = await res.json();
{ cache: 'no-store' }
옵션을 사용하면 해당 요청은 캐싱되지 않는다. 그렇기 때문에 SSR의 방식으로 페이지를 구성할 수 있다.
Request Memoization은 서버 컴포넌트 렌더링 중 동일한 fetch
요청이 여러 번 호출되더라도, 실제로는 한 번만 실행되도록 하는 기능이다. 이를 통해 불필요한 중복 네트워크 요청을 방지하고, 서버 자원과 응답 시간을 최적화할 수 있다. 이 점이 내가 서버 컴포넌트에서는 어떻게 데이터가 공유를 할 수 있을까 하면서 고민했던 점인데 이미 강의에서도 한번 했던 내용,, 정신채리
예를 들어, 컴포넌트 트리의 여러 곳에서 동일한 데이터를 필요로 할 때:
async function getCommonData() {
const res = await fetch('<https://api.example.com/common-data>');
return res.json();
}
// 컴포넌트 A에서 데이터 호출
const dataA = await getCommonData();
// 컴포넌트 B에서 동일한 데이터 호출
const dataB = await getCommonData();
위 코드에서 getCommonData
함수는 두 번 호출되었지만, 실제 네트워크 요청은 한 번만 발생한다. 두 번째 호출에서는 첫 번째 호출의 결과를 재사용한다.
이러한 메모이제이션은 React의 기능으로, 서버 컴포넌트 렌더링 과정에서만 적용된다. 렌더링이 완료되면 메모리에 저장된 캐시는 제거되며, 다음 요청 시에는 다시 초기화된다.
Next.js에는 레이아웃, 로딩 상태 및 페이지별로 분할된 경로 세그먼트의 RSC 페이로드를 저장하는 인메모리 클라이언트 측 라우터 캐시가 있다. 사용자가 경로 사이를 탐색할 때 Next.js는 방문한 경로 세그먼트를 캐시하고 사용자가 탐색할 가능성이 있는 경로를 미리 가져온다. 그 결과 즉각적인 앞,뒤로 탐색하고 탐색 간에 전체 페이지를 다시 로드하지 않으며 React 상태와 브라우저 상태를 보존할 수 있다.
어우 Next.js를 사용하기 위해서는 이러한 캐시 전략들을 모두 알고 사용해야 이 프레임워크를 제대로 사용할 줄 안다 라고 할 수 있을 것 같다. 많이 헷갈리지만 어쩔 수 없지