[Next.js 13 공식 문서 번역하기] Caching Data

Yewon Jeong·2023년 5월 27일
2

next.js는 요청별(권장) 또는 전체 경로 세그먼트 모두에서 데이터 캐싱을 기본적으로 지원한다.

Per-request Caching

fetch()

기본적으로, 모든 fetct() 요청은 캐시되고 자동으로 중복제거 된다. 즉, 만약 같은 요청을 두번 생성한다면 두번째 요청은 첫번째 요청의 결과를 재사용 될 것이다.

async function getComments() {
  const res = await fetch('https://...'); // The result is cached
  return res.json();
}
 
// This function is called twice, but the result is only fetched once
const comments = await getComments(); // cache MISS
 
// The second call could be anywhere in your application
const comments = await getComments(); // cache HIT

요청이 캐시되지 않는 경우:

  • 동적 메서드(next/headers,export const POST,등)들이 사용되고 fetch가 POST요청인 경우(또는 Authorization이나 cookie 헤더를 사용하는 경우)
  • fetchCache는 기본적으로 캐시를 건너뛰도록 구성되어 있다.
  • revalidate: 0 또는 cache: 'no-store' 이 개별 fetch에 구성되어 있다.

fetch를 사용하여 만든 요청은 요청의 재검증 빈도를 제어하는 옵션을 지정할 수 있다.

export default async function Page() {
  // revalidate this data every 10 seconds at most
  const res = await fetch('https://...', { next: { revalidate: 10 } });
  const data = res.json();
  // ...
}

React cache()

React를 사용하면 래핑된 함수 호출의 결과를 메모하면서 캐시하고 중복제거할 수 있다. 동일한 인수로 호출된 동일한 함수는 함수를 다시 실행하는 대신 캐시된 값을 재사용한다.

import { cache } from 'react';
 
export const getUser = cache(async (id: string) => {
  const user = await db.user.findUnique({ id });
  return user;
});
import { getUser } from '@utils/getUser';
 
export default async function UserLayout({ params: { id } }) {
  const user = await getUser(id);
  // ...
}
import { getUser } from '@utils/getUser';
 
export default async function Page({
  params: { id },
}: {
  params: { id: string };
}) {
  const user = await getUser(id);
  // ...
}

위 예제에서 getUser() 함수를 두 번 호출하더라도 데이터베이스에 대한 쿼리는 한 번만 수행된다. 이는 getUser()가 cache()에 래핑되어 두 번째 요청이 첫 번째 요청의 결과를 재사용할 수 있기 때문이다.

알아두면 좋은 사실

  • fetch()는 요청을 자동으로 캐시하므로 fetch()를 사용하는 함수를 cache()로 래핑할 필요가 없다. 자세한 내용은 automatic request deduping 문서를 참조하라.
  • 이 새로운 모델에서는 여러 컴포넌트에서 동일한 데이터를 요청하더라도 구성 요소 간에 데이터를 props로 전달하는 대신 데이터가 필요한 컴포넌트에서 직접 데이터를 fetch하는 것을 권장한다.
  • 서버 데이터 fetch 기능이 클라이언트에서 사용되지 않도록 서버 전용 패키지를 사용하는 것을 권장한다.

POST requests and cache()

POST 요청은 POST 경로 핸들러 내부에 있거나 headers()/cookies()를 읽은 후에 오지 않는 한 fetch를 사용할 때 자동으로 중복 제거된다. 예를 들어 위의 경우에 GraphQL 및 POST 요청을 사용하는 경우 캐시를 사용하여 요청을 중복 제거할 수 있다. 캐시 인수는 무계층이어야 하며 원시변수만 포함해야 한다. 심층 개체는 중복 제거와 일치하지 않는다.

import { cache } from 'react';
 
export const getUser = cache(async (id: string) => {
  const res = await fetch('...', { method: 'POST', body: '...' });
  // ...
});

Preload pattern with cache()

패턴으로서 데이터를 fetch하는 컴포넌트나 유틸리티 함수에서 preload() export를 선택적으로 노출할 것을 제안한다.

import { getUser } from '@utils/getUser';
 
export const preload = (id: string) => {
  // void evaluates the given expression and returns undefined
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
  void getUser(id);
};
export default async function User({ id }: { id: string }) {
  const result = await getUser(id);
  // ...
}

preload를 호출하면 필요할 것 같은 데이터를 적극적으로 가져올 수 있
다.

import User, { preload } from '@components/User';
 
export default async function Page({
  params: { id },
}: {
  params: { id: string };
}) {
  preload(id); // starting loading the user data now
  const condition = await fetchCondition();
  return condition ? <User id={id} /> : null;
}

알아두면 좋은 사실.

  • preload()는 다른 이름을 가질 수 있다. 이것은 패턴일 뿐이지 api가 아니다.
  • 이 팬턴은 선택일 뿐이며 사례별로 최적화하는 데 사용할 수 있다. 이 패턴은 병렬 데이터 fetch 위에 추가로 최적화된다. 이제 promise를 prop으로 전달할 필요가 없고 대신 preload 패턴에 의존할 수 있다.

Combining cache, preload, and server-only

캐시 기능, preload 패턴 및 서버 전용 패키지를 결합하여 앱 전체에서 사용할 수 있는 data fetch 유틸리티를 만들 수 있다.

import { cache } from 'react';
import 'server-only';
 
export const preload = (id: string) => {
  void getUser(id);
};
 
export const getUser = cache(async (id: string) => {
  // ...
});

이 접근 방식을 사용하면 적극적으로 데이터를 가져오고, 응답을 캐시하고, 이 데이터 가져오기가 서버에서만 발생하도록 보장할 수 있다.

getUser.ts 내보내기는 레이아웃, 페이지 또는 구성 요소에서 사용하여 사용자 데이터를 가져오는 시기를 제어할 수 있다.

Segment-level Caching

참고: 캐싱에 대한 세분화 및 제어를 개선하려면 요청당 캐싱을 사용하는 것을 권장한다.

세그먼트 수준 캐싱을 사용하면 경로 세그먼트에 사용된 데이터를 캐시하고 재검증할 수 있다.

이 메커니즘을 사용하면 경로의 여러 세그먼트가 전체 경로의 캐시 수명을 제어할 수 있다. 경로 계층 구조의 각 page.tsx 및 layout.tsx는 경로의 재검증 시간을 설정하는 재검증 값을 내보낼 수 있다.

export const revalidate = 60; // revalidate this segment every 60 seconds

알아두면 좋은 사실.

  • 페이지, 레이아웃 및 컴포넌트 내부의 fetch 요청이 모두 재검증 빈도를 지정하는 경우 세 가지 중 가장 낮은 값이 사용됩니다.
  • 고급: fetchCache를 'only-cache' 또는 'force-cache'로 설정하여 모든 가져오기 요청이 캐싱을 선택하도록 할 수 있지만 재검증 빈도는 여전히 개별 가져오기 요청에 의해 낮아질 수 있다. 자세한 내용은 fetchCache를 참조하라.

참고
https://nextjs.org/docs/app/building-your-application/data-fetching/caching

profile
일단 하는 중

0개의 댓글