Post

Next.js 13의 특징과 변화(4) - Data Fetching

📌시작하며

현재 만들고 있는 프로젝트에서는 첫 화면에서 DB에 있는 data를 불러와 렌더링해서 보여주려고 한다.😎
useQuery를 써서 불러올까 했지만, Next13의 data Fetching 기능을 사용해보고 싶기도 했고, 프로젝트 내의 다른에서 무한 스크롤을 적용해 데이터를 전부 가져올 예정이기 때문에, 루트 페이지에서는 겹치지 않는 기능을 구현해보기로 결정했다.

✅next13의 변경점

처음에, next12에서 사용하던 data fetching 부분이 next13에서 변경된 건 알겠지만.. 내가 알던 getStaticProps은 next13문서 어디에 적혀있는가..?🥲 하며 헤맸는데, 결론부터 말하면 이 부분이 next13에서 삭제되었고, 좀더 쉬운 방식으로 구현할 수 있도록 변경되었다!

하지만 전체적인 ‘구현 결과와 목적’ 은 비슷하기 때문에 함께 짚어보고자 한다.

✅ fetch()

next13 data fetching을 이해하기 위해서는 먼저 fetch() API를 이해해야 한다.

Next.js는 native Web fetch() API를 확장해 서버의 각 요청이 고유한 지속적인 캐싱 시멘틱을 설정할 수 있도록 한다.

브라우저에서 cache 옵션은 fetch 요청이 브라우저의 HTTP 캐시와 상호 작용하는 방식을 나타내지만, Next.js의 fetch() API확장을 통해 cache는 서버 측으 fetch 요청이 프레임워크의 지속적인 HTTP 캐시와 상호 작용하는 방식을 나타내게 된다.

즉, Next.js의 fetch()의 cache 옵션은 브라우저 캐시와는 관련이 없고, 서버 측에서의 데이터 캐싱과 관련이 되어있다는 뜻이다.

또한, 서버 컴포넌트 내에서 직접 async 및 await을 사용하여 fetch를 호출할 수 있다.

➡️fetch() options

request가 Next.js 데이터 캐시와 상호 작용하는 방식을 결정한다.

1
fetch(`https://...`, { cache: "force-cache" | "no-store" })

force-cache(default)- Next.js는 데이터 캐시에서 일치하는 request를 찾는다. 만약 일치하는 항목이 있고, 새 항목이라면 캐시에서 반환된다.

만약, 일치하는 항목이 없거나 오래된 항목인 경우 Next.js는 원격 서버에서 리소스를 가져와 다운로드한 리소스로 캐시를 업데이트한다.

no-store - Next.js는 캐시를 확인하지 않고 요청할 때마다 원격 서버에서 리소스를 가져오며, 다운로드한 리소스로 캐시를 업데이트하지 않는다.

캐시 옵션을 제공하지 않으면 cookies()와 같은 동적 함수를 사용하지 않는 한 Next.js는 기본적으로 force-cache로 설정되며, 이 경우 no-store로 기본 설정된다. no-cache 옵션은 Next.js에서 no-store와 동일한 방식으로 작동한다.

➡️options.next.revalidate

1
fetch(`https://...`, { next: { revalidate: false | 0 | number } })

리소스의 캐시의 수명(초)을 설정한다.

false - 리소스를 무기한으로 캐시한다. 의미적으로 revalidate: Infinity와 동일하다. 시간이 지남에 따라 HTTP 캐시는 이전 리소스를 제거할 수 있다. 0 - 리소스가 캐시되지 않도록 한다. number - (초 단위) 리소스의 캐시 수명을 최대 n초로 지정한다.

  • 개별 fetch()요청의 revalidate의 숫자가 route의 default revalidate숫자보다 작다면, 전체 route의 revalidation 시간이 감소한다.
  • 동일한 URL에 revalidation이 다른 두 개의 fetch 요청이 존재한다면, 작은 값을 가진 fetch 요청이 사용된다.

  • revalidate가 숫자로 설정된 경우 cache 옵션을 설정할 필요가 없다. 0은 cache: 'no-store'를 의미하고 양수 값은 cache: 'force-cache'를 의미한다.
  • 충돌하는 옵션인 { revalidate: 0, cache: 'force-cache' } 또는 { revalidate: 10, cache: 'no-store' }는 오류를 발생시킨다.

➡️options.next.tags

1
fetch(`https://...`, { next: { tags: ["collection"] } })

리소스의 캐시 태그를 설정한다. revalidateTag를 사용해 필요할 때마다 데이터를 revalidate할 수 있다. 사용자 정의 태그의 최대 길이는 256자이며 최대 태그 항목 수는 64개다.

✅getStaticProps

페이지에서 getStaticProps(정적 사이트 생성)라는 함수를 내보내면 Next.js는 빌드 시점에 getStaticProps가 반환한 props를 사용하여 이 페이지를 미리 렌더링한다.

getStaticProps는 항상 서버에서 실행되며 클라이언트에서는 실행되지 않는다.

➡️사용되는 상황

  1. 페이지를 렌더링하는 데 필요한 데이터가 사용자 요청 전, 빌드 시점에 사용 가능한 경우
  2. 데이터가 headless CMS에서 가져오는 경우
  3. 페이지가 사전 렌더링(검색 엔진 최적화를 위해)되어야 하고 매우 빠른 속도를 제공해야 하는 경우
  4. 데이터가 공개 캐시될 수 있는 경우

➡️next13 에서의 구현

next13에서는 다음과 같은 방식으로 getStaticProps와 유사하게 구현할 수 있다.

1
2
3
4
5
6
7
8
export default async function Page() {
  // 이 요청은 수동으로 무효화 될 때까지 캐시되어야 한다.
  // getStaticProps와 유사하다.
  // force-cache는 기본값이며 생략할 수 있다.
  const staticData = await fetch(`https://...`, { cache: "force-cache" })

  return <div>...</div>
}

➡️revalidate 적용

1
2
3
4
5
6
7
8
9
export default async function Page() {
  // 이 요청은 10초 동안 캐시되어야 한다.
  // revalidate 옵션을 사용한 getStaticProps와 유사하다.
  const revalidatedData = await fetch(`https://...`, {
    next: { revalidate: 10 },
  })

  return <div>...</div>
}

✅getServerSideProps

getServerSideProps는 요청 시 데이터를 가져오고 페이지의 콘텐츠를 렌더링하는 데 사용할 수 있는 Next.js 함수다.

➡️사용되는 상황

개인화된 사용자 데이터, 요청 시에만 알 수 있는 정보에 의존하는 페이지를 렌더링해야 하는 경우에 getServerSideProps를 사용한다. (ex)인증 헤더나 지리적 위치와 같은 정보)

➡️next13 에서의 구현

next13에서는 다음과 같은 방식으로 getServerSideProps와 유사하게 구현할 수 있다.

1
2
3
4
5
6
7
export default async function Page() {
  // 이 요청은 모든 request에서 refetch되어야 한다.
  // getServerSideProps와 유사하다.
  const dynamicData = await fetch(`https://...`, { cache: "no-store" })

  return <div>...</div>
}

📩마무리

이렇게 정리하니, 어떻게 사용해야 할지 감이 잡힌다.😎 이후에는 실제 구현하고 구현 코드를 추가할 예정이다.

🗂️참고 사이트

This post is licensed under CC BY 4.0 by the author.