[유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 2기 - 12일차(RSC/RCC, 시스템 파일, 메타 데이터, 병렬 패칭, 캐싱)

김하은·2024년 8월 3일
0
post-thumbnail

🧐 회고

1. 배운 것 (핵심 내용 & 인사이트)

  • RSC와 RCC의 개념과 차이: 서버 컴포넌트와 클라이언트 컴포넌트의 역할과 사용법을 명확히 이해하게 됨
  • Next.js 14의 시스템 파일 종류와 특징: 다양한 시스템 파일(page, layout, error 등)의 역할을 학습하고, 이를 효율적으로 활용하는 방법을 익힘
  • 병렬 패칭 방법: Promise.all, 컴포넌트 분리, Suspense를 활용한 병렬 데이터 패칭 기법을 배움
  • Next.js의 캐싱 시스템: Next.js의 다양한 캐싱 메커니즘과 작동 방식을 이해하고, 이를 통해 성능을 최적화하는 방법을 알게 됨

2. 앞으로 더 조사해볼 내용

  • 캐시와 관련된 직접 코드 실행: 학습한 내용을 코드로 직접 구현하고 테스트하여 실습 경험을 쌓기
  • Next.js에서의 코드 분할 필요 여부: Next.js가 자동으로 코드 분할을 처리하는지, 추가적인 설정이 필요한지 조사하기
  • 리액트 트리 상단에서 RCC 사용 시 대처법: RCC를 리액트 트리 상단에서 사용할 때 발생할 수 있는 문제와 그 해결 방법을 더 알아보기

3. 앞으로 적용해야겠다고 느낀 점

  • Next.js 14의 캐싱 시스템 활용: 데이터가 원하는 대로 업데이트되지 않을 때 캐싱 시스템을 활용하는 방법 익히기
  • Suspense를 이용한 병렬 데이터 패칭: 효율적인 데이터 패칭을 위해 Suspense를 적극 활용하기

4. 학습 평가 및 다짐/목표

Next.js 14와 관련된 새로운 기능과 개념을 잘 이해하고 이를 응용할 수 있는 능력을 키울 수 있었다. 배운 이론을 적절하게 적용할 수 있도록 실제 프로젝트를 해보고, 더 깊이 있는 연구와 실험을 해봐야 할 것 같다.


📒 학습 내용

Next.js에서 서버 컴포넌트와 클라이언트 컴포넌트

서버 컴포넌트 (RSC, React Server Component)

서버에서만 렌더링되고 클라이언트(브라우저)로 전송되지 않는 컴포넌트로, data fetching을 주로 담당함

  • 사용법: 모든 컴포넌트는 기본적으로 서버 컴포넌트로 간주됨
  • data fetching: axiosfetch 등을 사용하여 데이터를 서버에서 요청할 수 있음
  • 비동기 처리: 컴포넌트에서 asyncawait를 사용하여 비동기 작업을 처리할 수 있음
  • 훅 사용 불가: 서버 컴포넌트에서는 React 훅을 사용할 수 없음

➡️ RSC로 data fetching을 하는 이유
서버에서 데이터를 빠르게 가져와 클라이언트 측에서의 데이터 로딩 시간을 줄여 사용자 경험을 개선할 수 있음

클라이언트 컴포넌트 (RCC, React Client Component)

클라이언트 컴포넌트는 브라우저에서 실행되며, 사용자와의 상호작용을 처리함

  • 사용법: 클라이언트 컴포넌트를 사용하려면 use client 지시어를 추가해야 함
  • 사용자 상호작용: 버튼 클릭, 폼 제출 등 사용자와의 직접적인 상호작용을 처리함
  • 훅 사용 가능: useState, useEffect와 같은 React 훅을 사용할 수 있음
  • 이중 렌더링: 클라이언트 컴포넌트는 서버와 클라이언트에서 각각 한 번씩 렌더링되며 이는 성능에 큰 영향을 주지 않음

컴포넌트 트리 구조

클라이언트 컴포넌트 밑에 서버 컴포넌트가 있으면 더 이상 서버 컴포넌트로서의 역할을 못 하므로
루트에 서버 컴포넌트를 두고 컴포넌트 트리의 말단으로 클라이언트 컴포넌트를 밀어 넣는 것이 좋음

정말 클라이언트 컴포넌트는 내부에서 서버 컴포넌트가 제 역할을 못하는지 알아보자.

Case 1. RSC -> RCC

  • 터미널: console.log로 메세지를 찍었을 때 터미널에도 RCC의 메세지가 나옴 -> RCC는 서버에서도 렌더링 된다는 사실을 알 수 있음
  • 브라우저 콘솔: 브라우저의 콘솔에는 RSC의 메세지는 나오지 않고 RCC의 메세지만 나옴 -> RSC는 서버에서만 렌더링 됐고, RCC는 클라이언트에서도 렌더링 된다는 사실을 알 수 있음

Case 2. RCC -> RSC

  • 터미널: Case 1처럼 터미널에 나온 메세지를 미루어 보아 RSC, RCC 모두 서버에서 렌더링 됐음을 알 수 있음
  • 브라우저 콘솔: Case 1과 달리 RSC의 메세지가 브라우저 콘솔에 찍힘 -> 서버에서만 렌더링 돼야 하는 RSC의 역할을 제대로 하지 못하는 것을 알 수 있음

➕ 참고하면 좋은 글

Section 02 - 시스템 파일과 메타데이터

page

page.tsx: 라우트의 경로를 지정할 때 사용하는 페이지

layout

layout.tsx: Next.js는 각 라우트 경로마다 layout.tsx 파일을 지정하여 공통된 레이아웃을 처리해줄 수 있음

루트 레이아웃

  • 하나의 Next.js 애플리케이션에서는 반드시 필수로 필요함
  • 가장 최상단의 라우트 경로에 생성됨
  • Next.js 시스템에 의해 자동으로 생성됨

라우트 레이아웃

  • 각 라우트 경로마다 개별적으로 설정 가능한 레이아웃
  • 경로마다 생성하면 레이아웃을 중첩할 수 있음

not-found

not-found.tsx: 페이지를 찾을 수 없을 때 보이는 페이지

  • 가장 최상위 즉, 루트의 not-found를 보여주는 것이 일반적임
  • 경로 마다 다른 not-found를 보여주고 싶다면 notFound함수를 이용해야 함
    • 이 경우 가장 가까운 경로의 not-found를 보여줌
      if (params.id === "2") notFound();

error

error.tsx: 컴포넌트에서 에러가 발생했을 때 사용자에게 보여주는 커스텀 페이지

  • ‘use client’를 사용해야 하는 클라이언트 컴포넌트임
  • 자신의 라우트 경로와 가장 가까이에 있는 error.tsx 컴포넌트를 우선 렌더링함
  • errorreset 객체를 props로 받을 수 있음
    • error message를 이용할 수 있음
    • reset: 클라이언트 컴포넌트에서 발생한 error를 복구할 수 있음 -> error가 발생한 페이지에 CSR을 다시 해줌

loading

loading.tsx: 컴포넌트의 로딩 상태를 관리해 주는 페이지

  • 자신의 라우트 경로와 가장 가까이에 있는 loading.tsx 컴포넌트를 우선 렌더링함
  • loading.tsx 파일이 없으면 서버 컴포넌트 로딩 발생시 화면이 표시되지 않음

메타 데이터 (Meta Data)

SEO (Search Engine Optimization)

검색 엔진 최적화, 검색 엔진에서 사이트의 노출도를 올리게 하는 코드 최적화 기법으로 크게 두가지 방법으로 나눌 수 있음

  1. 메타 데이터 올바르게 사용하기
  2. HTML 마크업 시맨틱하게 작성하기

Next.js 14에서 메타 데이터 정의 방법

1. 정적 메타 데이터 객체

metadata 변수로 정의한 객체를 내보내는 방법

export const metadata = {
	title: "Meta Data Welcome!"
}

2. 동적 메타 데이터 생성 함수

약속된 함수 generateMetadata()를 정의해서 내보내는 방법으로 앞으로 더 공부해 볼 것!

메타 데이터에서 사용할 수 있는 속성

Metadata Object and generateMetadata Options

title에 동일한 텍스트 넣는 법

  • title을 템플릿 처럼 사용할 수 있는 방법
  • default는 필수 값으로 해당 페이지에 나타낼 텍스트도 됨
export const metadata: Metadata = {
  title: { template: '%s | 수코딩', default: 'Home | 수코딩' },
  description: 'Generated by create next app',
};

Section 03 - 데이터 패칭

병렬 fetching

방법 1. Promise.all

  • 요청을 병렬적으로 처리할 수 있음
async function getData() {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const data = await res.json();
  return data;
}

async function getData2() {
  await new Promise((resolve) => setTimeout(resolve, 2000));
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const data = await res.json();
  return data;
}

export default async function Home() {
  const [data, data2] = await Promise.all([getData(), getData2()]);

  return (
    <>
      {JSON.stringify(data, null, 2)}
      <hr />
      {JSON.stringify(data2, null, 2)}
    </>
  );
}

방법 2. 컴포넌트 분리

  • 요청을 병렬적으로 처리할 수 있음
  • loading.tsx 컴포넌트 상태를 공유함
  • 전체 로딩 상태는 가장 오래 걸리는 요청을 기준으로 결정됨
// page.tsx
import Fetching1 from '@/components/Fetching1';
import Fetching2 from '@/components/Fetching2';

export default function Home() {
  return (
    <>
      <Fetching1 />
      <Fetching2 />
    </>
  );
}
// Fetching1.tsx
async function getData() {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  const res = await fetch('https://jsonplaceholder.typicode.com/posts');
  const data = await res.json();
  return data;
}

export default async function Fetching1() {
  const data = await getData();
  return (
    <>
      <h1>Fetching1</h1>
      {JSON.stringify(data, null, 2)}
    </>
  );
}

방법 3. Suspense

  • 각각의 요청을 병렬적 + 개별적으로 로딩할 수 있음
  • 데이터가 로드되는 동안 부분적으로 UI를 스트리밍할 수 있게 해줌
import Fetching1 from '@/components/Fetching1';
import Fetching2 from '@/components/Fetching2';
import { Suspense } from 'react';

export default function Home() {
  return (
    <>
      <h1>Home</h1>
      <Suspense fallback={<h1>loading1...</h1>}>
        <Fetching1 />
      </Suspense>
      <Suspense fallback={<h1>loading2...</h1>}>
        <Fetching2 />
      </Suspense>
    </>
  );
}

➕ 참고하면 좋은 글

Streaming

Next.js의 캐싱 시스템

자주 사용하는 데이터를 메모리에 저장해놓고 빠르게 가져와서 쓰는 시스템

➕ 필독 글

Caching in Next.js

💡 실무 팁

정확한 캐싱 적용을 위해서 개발자 모드는 끄고 코드 실행하기

4가지 캐싱의 종류

  • 우선순위: Router Cache > Full Route Cache > Request Memoization > Data Cache

1. Router Cache

Next.js 애플리케이션에서 브라우저 측에서 작동하는 임시 데이터 저장 시스템으로 사용자가 페이지를 이동할 때 더 빠른 내비게이션을 제공할 수 있음

사용자가 웹사이트를 탐색하는 동안 RSC Payload(React Server Component Payload)를 개별 라우트 세그먼트 단위로 나누어 브라우저의 임시 메모리에 저장함

저장된 데이터는 사용자 세션 동안 유지되며, 페이지 이동 시 서버 요청 없이 빠른 로딩을 가능하게 함
다만, 사용자가 웹사이트를 떠나거나 페이지를 새로 고침하면 이 캐시는 삭제됨

📍RSC Payload (React Server Component Payload)

  • 렌더링된 React 서버 컴포넌트 트리를 압축된 이진 형태로 표현한 데이터로 클라이언트에서 React가 브라우저의 DOM을 업데이트하는 데 사용됨
  • RSC Payload는 다음을 포함함
    • 서버 컴포넌트의 렌더링 결과
    • 클라이언트 컴포넌트가 렌더링될 위치의 자리 표시자와 해당 JavaScript 파일에 대한 참조
    • 서버 컴포넌트에서 클러이언트 컴포넌트로 전달된 모든 props

즉, 서버 컴포넌트의 렌더링 결과물을 포함하는 데이터를 의미하며, 주로 서버에서 클라이언트로 전송되는 HTML과 초기화된 상태 데이터를 포함함

작동 방식

  • 사용자가 라우트와 라우트를 이동할 때 즉, 내비게이션을 할 때 Next.js는 방문한 라우트 세그먼트를 캐시함
  • 사용자가 이동할 라우트를 prefetch함(이는 주로 사용자의 화면에 보이는 <Link> 컴포넌트를 기반으로 예측됨)

    (이 때 layout은 link때문이 아니므로 30초가 지나도 변하지 않음)

효과

사용자에게 향상된 내비게이션 경험을 제공할 수 있음

  • 방문한 라우트가 캐시되어 즉시 앞뒤로 이동할 수 있음
  • prefetching과 부분 렌더링 덕분에 새로운 라우트로 빠르게 이동할 수 있음
  • 내비게이션 할 때 전체 페이지가 새로고침되지 않고 React 상태와 브라우저 상태가 유지됨

지속 시간

캐시는 브라우저의 임시 메모리에 저장되는데 지속 시간은 두 가지 요인에 의해 결정됨

  1. 세션:

    • 캐시는 내비게이션할 때는 유지되지만 페이지를 새로 고침하면 지워짐
  2. 자동 무효화 기간:

    • 개별 세그먼트의 캐시는 일정 시간이 지나면 자동으로 무효화됩니다. 이 기간은 리소스가 미리 가져온 방식에 따라 달라집니다:
      • 기본 프리패칭(prefetch={null} 또는 미지정): 30초
      • 전체 프리패칭(prefetch={true} 또는 router.prefetch): 5분

페이지 새로 고침은 모든 캐시된 세그먼트를 지우지만, 자동 무효화 기간은 개별 세그먼트가 미리 가져온 시점부터 적용됩니다.

캐시 무효화 방법

라우터 캐시를 무효화 하는 방법은 두 가지가 있음

  1. Server Action

    • revalidatePath 또는 revalidateTag 함수 이용
  2. router.refresh 호출

    • router.refresh를 호출하면 라우터 캐시가 무효화되고, 현재 사용자가 보고 있는 페이지에 대해 서버로부터 최신 데이터를 다시 요청함
    • 서버는 최신 데이터를 응답으로 보내고, 브라우저는 이 데이터를 사용하여 페이지를 업데이트함

옵트 아웃

  • 라우터 캐시를 완전히 비활성화할 수는 없음
  • 따라서 위에 작성한 캐시 무효화 방법을 사용해야 함
  • <Link> 컴포넌트의 prefetch 속성을 false로 설정하여 프리패칭을 비활성화할 수 있음
    • 하지만 이 경우에도:
      • 사용자가 한 번 방문한 경로 세그먼트는 30초 동안 임시로 저장됨
      • 즉각적인 내비게이션이 가능함
      • 방문한 라우트는 여전히 캐시됨

장점:

  • 빠른 내비게이션: 페이지 이동 시 캐시된 데이터를 사용하여 빠르게 로드할 수 있음
  • 서버 요청 감소: 자주 방문하는 페이지에 대해 반복적인 서버 요청을 줄여줌
  • 사용자 경험 향상: 빠른 페이지 로딩으로 더 나은 사용자 경험을 제공함

2. Full Route Cache

Next.js에서 서버 측에서 작동하는 캐시 시스템으로, HTML과 RSC Payload를 저장함

이는 사용자가 페이지를 요청할 때마다 서버에서 다시 렌더링하지 않고 캐시된 결과를 제공함으로써 빠른 로딩 속도를 제공함

Full Route Cache는 빌드 시 또는 재검증 시 정적으로 렌더링된 라우트를 서버에 캐시하며 이를 통해 서버 요청에 대한 렌더링 비용을 줄이고 성능을 향상시킴

작동 방식

  1. 서버에서의 React 렌더링:

    • Next.js는 React의 API를 사용하여 서버에서 렌더링 작업을 수행함
    • 렌더링 작업은 개별 라우트 세그먼트와 서스펜스를 기준으로 나뉨
    • React는 서버 컴포넌트를 특수한 데이터 형식으로 렌더링하고 이를 RSC Payload라고 함
    • RSC Payload와 클라이언트 컴포넌트의 JavaScript를 사용하여 HTML을 서버에서 렌더링함
  2. 서버에서의 캐싱:

    • 렌더링된 결과(RSC Payload와 HTML)를 서버에 캐시함
    • 이는 정적으로 렌더링된 라우트에 적용됨
  3. 클라이언트에서의 React 하이드레이션 및 조정:
    클라이언트에서 요청시,

    • RSC와 RCC의 유저와 상호작용이 안되는 상태의 HTML을 빠르게 보여줌
    • RSC Payload를 사용하여 클라이언트와 렌더링된 서버 컴포넌트 트리를 조정하고 DOM을 업데이트함
    • JavaScript 명령을 사용하여 클라이언트 컴포넌트를 하이드레이트하고 애플리케이션을 상호작용 가능하게 만듦
  4. 클라이언트에서의 캐싱 (라우터 캐시)
    위에서 언급한 라우터 캐시 과정을 통해 RSC Payload는 클라이언트 측 라우터 캐시에 저장됨

  5. 이후 내비게이션 시

    • 이후의 내비게이션이나 프리패칭 중 라우터 캐시에 RSC payload가 저장돼 있는지 확인하고 저장돼 있다면 서버에 새로운 요청을 보내지 않음
    • 만약 라우트 세그먼트가 캐시에 없으면 RSC Payload를 서버에서 가져온 후 클라이언트 라우터 캐시에 저장함

📍정적 렌더링 vs. 동적 렌더링
라우트가 빌드 시에 캐시되는지 여부는 해당 라우트가 정적으로 렌더링되는지 동적으로 렌더링되는지에 따라 다름
정적 라우트는 기본적으로 캐시되지만, 동적 라우트는 요청 시에 렌더링되며 캐시되지 않음

아래 그림은 정적으로 렌더링된 라우트와 동적으로 렌더링된 라우트 간의 차이를, 캐시된 데이터와 캐시되지 않은 데이터를 통해 보여줌

지속 시간

기본적으로 Full Route Cache는 계속 유지됨
즉, 한 번 렌더링된 페이지 결과가 여러 사용자가 요청할 때마다 계속 사용된다는 뜻임

캐시 무효화 방법

Full Route Cache를 무효화 하는 방법은 2가지가 있음

  1. 데이터 재검증:
    • Data Cache를 재검증(Revalidating)하면 라우터 캐시가 무효화되고, 서버에서 컴포넌트를 리렌더링하여 새로운 렌더링 결과를 캐시함
  2. 재배포:
    • Data Cache와 달리 새로운 배포 시 Full Route Cache는 삭제됨

옵트 아웃

Full Route Cache를 사용하지 않도록 설정해서 모든 요청마다 동적으로 컴포넌트를 렌더링 할 수 있음

  • 동적 함수 사용: 이 방법을 사용하면 해당 라우트를 풀 라우트 캐시에서 제외하고 요청 시마다 동적으로 렌더링할 수 있으며 Data Cache는 여전히 사용할 수 있음
  • dynamic = 'force-dynamic' 또는 revalidate = 0 라우트 세그먼트 설정 옵션을 사용하면 Full Route Cache와 Data Cache를 건너뛸 수 있음
    • 즉, 서버에 들어오는 모든 요청마다 컴포넌트가 렌더링되고 데이터를 새로 가져옴
    • 라우터 캐시는 클라이언트 측 캐시이므로 여전히 적용됨
  • Data Cache 옵트 아웃: 만약 특정 라우트에 캐시되지 않는 fetch 요청이 있다면, 이 라우트는 Full Route Cache에서 제외됨
    • 해당 fetch 요청의 데이터는 들어오는 모든 요청마다 새로 가져오게 됨
    • 옵트 아웃하지 않은 다른 fetch 요청은 여전히 Data Cache에 저장되며 이를 통해 캐시된 데이터와 캐시되지 않은 데이터를 혼합하여 사용할 수 있음

Router Cache와 Full Route Cache의 차이점

  • 라우터 캐시는 사용자 세션 동안 React 서버 컴포넌트 페이로드를 브라우저에 임시로 저장하는 반면, 풀 라우트 캐시는 여러 사용자가 요청할 때마다 서버에 RSC Payload와 HTML을 저장해 두고, 동일한 데이터를 반복해서 사용함
  • 풀 라우트 캐시는 정적으로 렌더링된 라우트만 캐시하는 반면, 라우터 캐시는 정적 및 동적으로 렌더링된 라우트 모두에 적용됩니다.

3. Request Memoization

React 컴포넌트 트리 내에서 동일한 URL과 옵션으로 fetch 요청을 할 때 자동으로 메모이제이션하는 기능
이를 통해 동일한 데이터를 여러 곳에서 사용할 때 중복된 네트워크 요청을 피할 수 있음

작동 방식

  1. 첫 번째 요청:

    • 처음 특정 요청이 호출되면 메모리에 저장되지 않아 캐시 미스가 발생함
    • 함수가 실행되고 외부 데이터 소스에서 데이터를 가져와 메모리에 저장함
  2. 이후 요청:

    • 동일한 요청이 동일한 렌더링 패스에서 다시 호출되면 캐시 히트가 발생하고 메모리에서 데이터를 반환함
    • 렌더링 패스가 완료되면 메모리 초기화와 함께 메모이제이션 항목이 지워짐

지속 시간

클라이언트가 서버에 요청을 보내고 서버가 그 요청에 대해 응답을 반환할 때까지 지속되며, React 컴포넌트 트리가 렌더링을 완료할 때까지 유지됨

재검증

Request Memoization은 서버 요청 간에 공유되지 않으므로 재검증이 필요 없음

옵트 아웃

  • 메모이제이션은 GET 메서드에만 적용됨
  • 개별 요청을 관리하려면 AbortController의 signal 속성을 사용할 수 있음

4. Data Cache

Next.js에는 가져온 데이터를 서버 요청과 배포 후에도 계속 유지하는 기능이 있음
이 기능은 Next.js가 fetch 기능을 확장하여, 서버에서 요청할 때마다 데이터를 캐시에 저장할 수 있도록 하기 때문에 가능함

기본적으로, fetch를 사용하여 데이터를 요청하면 그 데이터는 캐시되며 fetch의 cache와 next.revalidate 옵션을 사용하여 캐싱 동작을 설정할 수 있음

작동 방식

  1. 첫 번째 fetch 요청:

    • 렌더링 중에 fetch 요청이 처음 호출되면, Next.js는 Data Cache를 확인함
    • 캐시가 있으면 즉시 반환하고 메모이제이션 함
    • 캐시가 없으면 데이터 소스에 요청을 보내고 결과를 Data Cache에 저장하고 메모이제이션 함
  2. 캐시되지 않은 데이터:

    • 캐시되지 않은 데이터(예: { cache: 'no-store' } 설정)는 항상 데이터 소스에서 가져오고 메모이제이션됨

데이터가 캐시되었든 캐시되지 않았든, 동일한 데이터를 반복해서 요청하는 것을 피하기 위해 모든 요청은 메모이제이션됨

📍 Data Cache와 Request Memoization의 차이점
Data Cache와 Request Memoization 둘 다 캐시된 데이터를 재사용하여 성능을 향상시키지만, Data Cache는 여러 요청과 배포에 걸쳐 지속되는 반면, 메모이제이션은 요청 과정 동안(클라이언트가 서버에 요청을 보내고 서버가 그 요청에 대해 응답을 반환할 때까지)만 지속됨

  • Request Memoization을 사용하면 한 번의 렌더링 동안, 동일한 데이터를 여러 번 요청하는 경우 네트워크를 통해 데이터 캐시 서버(CDN 또는 엣지 네트워크)나 데이터 소스(데이터가 실제로 저장된 곳, 예: 데이터베이스 또는 CMS)에 중복된 요청을 보내는 것을 줄여줌
    • 예를 들어, 페이지를 렌더링하는 동안 동일한 데이터를 여러 컴포넌트에서 요청하면, 첫 번째 요청 후 메모이제이션된 데이터를 사용하여 다시 요청하지 않음
  • Data Cache는 여러 요청과 배포에 걸쳐 여러 사용자 요청이나 애플리케이션 배포 후에도 원본 데이터 소스로 보내는 요청의 수를 줄여줌
    • 예를 들어, 데이터를 한 번 캐시에 저장하면, 이후의 요청에서는 원본 데이터 소스가 아닌 캐시에서 데이터를 가져옴

요약하면, Request Memoization은 한 번의 렌더링 과정에서 동일한 데이터를 여러 번 요청하지 않도록 도와주고,
Data Cache는 여러 사용자 요청이나 애플리케이션 배포 후에도 데이터를 캐시에 저장하여 원본 데이터 소스로의 요청을 줄여줌

지속 시간

Data Cache는 기본적으로 계속 유지되며, 재검증하거나 옵트 아웃하지 않는 한 유지됨

재검증

  1. 시간 기반 재검증:
    • 일정 시간이 지나고 새로운 요청이 있을 때 데이터를 재검증함
    • 데이터가 자주 변경되지 않으면서 꼭 최신일 필요가 없는 경우에 유용함
// Revalidate at most every hour
fetch('https://...', { next: { revalidate: 3600 } })
  1. 온디맨드 재검증:
    • 이벤트 기반으로 데이터를 재검증함
    • 예를 들어, 폼 제출 시 태그(revalidateTag) 또는 경로(revalidatePath)에 따라 데이터를 재검증할 수 있음
    • 최신 데이터를 가능한 한 빨리 표시해야 할 때 유용함

옵트 아웃

  • fetch 요청에서 cache: 'no-store' 설정으로 캐싱을 비활성화할 수 있음
// 개별 `fetch` 요청에 대해 캐싱을 비활성화
fetch(`https://...`, { cache: 'no-store' })
  • 특정 라우트 세그먼트에 대해 캐싱을 비활성화할 수 있음
    • 해당 라우트 세그먼트에서 발생하는 모든 데이터 요청이 캐시되지 않으며, 서드 파티 라이브러리의 요청도 포함함
// 라우트 세그먼트 내의 모든 데이터 요청에 대해 캐싱을 비활성화
export const dynamic = 'force-dynamic'

📌 캐시 깔끔하게 지우는 법

  1. 서버 끄기
  2. about:blank로 이동
  3. .next.cache 파일지우기
  4. 개발 서버 다시 구동
  5. http://localhost:3000으로 이동

💡 React의 fetch API와 Next.js 14의 fetch API의 차이

  • 웹 API: 원래는 서버에서 사용할 수 없는 클라이언트 전용 API임
  • Next.js의 확장: Next.js 팀이 기존 fetch API를 래핑하여 서버 컴포넌트에서도 동작하도록 만들었음
    • next 속성을 추가하여 revalidate 같은 기능을 사용할 수 있게 함
    • 따라서 이름은 같지만 React에서 사용하던 fetch와는 다름
  • Axios 필요 없음: Axios도 서버에서 사용할 수 있도록 만들어진 라이브러리 이지만, Next.js의 확장된 fetch는 캐싱 제어(opt-out, revalidate 등) 기능을 제공하므로 굳이 Axios를 사용할 필요가 없음

➕ 더 알아볼 것

Next.js에서는 code splitting를 사용하지 않아도 되나?

——————————————————————————
본 후기는 본 후기는 [유데미x스나이퍼팩토리] 프로젝트 캠프 : Next.js 2기 과정(B-log) 리뷰로 작성 되었습니다.

profile
아이디어와 구현을 좋아합니다!

0개의 댓글