Next.js의 캐싱 매커니즘 첫 번째 ‘Request Memoization’

Cache

이 글은 2024-05-05에 작성되었어요.

프롤로그


유저 경험에서 빼놓을 수 없는 것이 ‘캐싱’이라고 생각하는데, 사용하고 있는 Next.js 전반에 걸쳐 어떤 방식으로 캐싱을 지원하고 있는지 좀 더 자세히 알아보고 싶어졌습니다.

그래서 오늘부터 총 네 가지의 캐싱 전략, 그 중에서도 ‘Request Memoization’에 대해서 알아보도록 하겠습니다.

요청 메모이제이션(Request Memoization)


리액트에서 동일한 데이터를 동일한 페이지의 여러 컴포넌트에서 표시해야 할 때 주로 발생하는 캐싱 방식입니다.

일반적으로는 위 상황을 구현하기 위해서는 ‘표시해야 하는 컴포넌트 마다 요청하여 N번 수행’ 또는 ‘여러 컴포넌트의 상위 컴포넌트에서 한 번 선언 후 Props로 전달’ 하는 방식을 사용해야 하는데요. 요청 메모이제이션을 이용하면 Store를 사용하는 것 처 이상적인 구현이 가능합니다.

요청 메모이제이션은 렌더링 주기(Render Cycle) 동안 서버 컴포넌트에서 수행되는 모든 요청을 캐시하는 React의 기능입니다.

예시와 함께 보겠습니다.

// 유저 데이터 요청 export async function fetchUserData(userId) { const response = await fetch(`https://api.example.com/users/${userId}`) return response.json() } export async function Parent({ userId }) { // 첫 번째 요청 - 해당 요청에 대해 캐시 const user = await fetchUserData(userId) return <> <h1>{user.name}</h1> <Child userId={userId} /> </> } async function Child({ userId }) { // 두 번째 요청 - 새롭게 요청하지 않고 캐시를 사용함 const user = await fetchUserData(userId) return <p>{user.name}</p> }

위 예시처럼 동일한 요청에 대해서 캐시가 되어있어 불필요한 요청이 줄어드는 장점이 있습니다.

대부분의 상황에서는 필요없겠지만, 캐시가 불필요한 경우에도 다음과 같은 방식으로 캐시를 사용하지 않을 수 있습니다.

async function fetchUserData(userId) { const { signal } = new AbortController() const res = await fetch(`https://api.example.com/users/${userId}`, { signal, }) return res.json() }

이 메모이제이션은 아래와 같은 특징을 가지고 있습니다.

  1. ‘서버’에 저장됨
  2. 단일 렌더링 주기 동안에만 유효함
  3. GET 메소드에만 유효함

참고 이미지


Untitled.png

Reference.


👉🏻 Finally Master Next.js's Most Complex Feature - Caching