본문 바로가기
기술, 개발/nextjs

6차 강의 노트 (데이터 페칭)

by Jaejin Sim 2025. 8. 28.
반응형

App Router의 데이터 페칭

Next.js App Router의 도입으로 데이터 페칭 방식이 근본적으로 변화했습니다. 서버 컴포넌트라는 새로운 개념이 기존의 복잡한 데이터 전달 방식을 어떻게 단순화했는지 살펴보겠습니다.

Page Router 시대의 데이터 페칭

기존 Page Router에서는 서버 사이드 데이터를 가져오기 위해 특별한 함수들을 사용해야 했습니다.

// Page Router 방식
export async function getServerSideProps() {
  const data = await fetch('...')
  return { props: { data } }
}

export async function getStaticProps() {
  // 빌드 타임에 실행
}

export function Page({ data }) {
  return <div>...</div>
}

이 방식의 문제점은 데이터 전달의 복잡성이었습니다. 서버에서 가져온 모든 데이터가 최상위 페이지 컴포넌트에만 전달되기 때문에, 하위 컴포넌트들은 props나 Context API를 통해 데이터를 전달받아야 했습니다.

App Router: 서버 컴포넌트의 혁신

App Router에서는 서버 컴포넌트 덕분에 이런 문제가 해결되었습니다.

핵심 변화점

  1. 컴포넌트에서 직접 async 사용 가능
    • 기존: 클라이언트 컴포넌트에서는 async 키워드 사용 불가 (브라우저 문제 발생 가능)
    • 현재: 서버 컴포넌트는 브라우저에서 실행되지 않으므로 async 사용 가능
  2. 데이터가 필요한 곳에서 직접 fetch
    • Next.js 공식 문서에서도 이 방식을 권장

실제 구현 예시

// 모든 책 데이터를 가져오는 컴포넌트
async function AllBooks() {
  const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`)

  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>
  }

  const allBooks: BookData[] = await response.json()

  return (
    <div>
      {allBooks.map((book) => (
        <BookItem key={book.id} {...book} />
      ))}
    </div>
  )
}

// 추천 책 데이터를 가져오는 컴포넌트
async function RecoBooks() {
  const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/random`)

  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>
  }

  const recoBooks: BookData[] = await response.json()

  return (
    <div>
      {recoBooks.map((book) => (
        <BookItem key={book.id} {...book} />
      ))}
    </div>
  )
}

// 메인 페이지
export default function Home() {
  return (
    <div className={style.container}>
      <section>
        <h3>지금 추천하는 도서</h3>
        <RecoBooks />
      </section>
      <section>
        <h3>등록된 모든 도서</h3>
        <AllBooks />
      </section>
    </div>
  )
}

환경변수 관리

반복되는 API URL은 환경변수로 관리합니다.

# .env
# NEXT_PUBLIC_ 접두사가 없으면 서버에서만 사용 가능
NEXT_PUBLIC_API_SERVER_URL=http://localhost:12345

const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`)

중요: Async 컴포넌트 사용법

React Server Component에서 async 컴포넌트는 JSX에서 바로 사용할 수 없습니다.

// ❌ 잘못된 사용법
<RecoBooks q={q} />

// ✅ 올바른 사용법
{await RecoBooks({ q })}

데이터 캐시: 성능 최적화의 핵심

Next.js는 fetch로 가져온 데이터를 서버에 캐싱하는 기능을 제공합니다.

캐시 옵션들

// 1. 무조건 캐싱 (한 번 호출 후 재호출 안됨)
await fetch('~/api', { cache: "force-cache" })

// 2. 캐싱하지 않음 (Next.js 15부터 기본값)
await fetch('~/api', { cache: "no-store" })

// 3. 특정 시간마다 캐시 업데이트 (Page Router의 ISR과 유사)
await fetch('~/api', { next: { revalidate: 3 } })

// 4. 필요시 수동으로 캐시 무효화
await fetch('~/api', { next: { tags: ['books'] } })
  • { cache: "force-cache" }:
    • 요청의 결과를 무조건 캐싱합니다.
    • 한 번 페칭한 데이터는 다시 네트워크 요청을 보내지 않습니다.
    • 페이지 라우터의 getStaticProps와 유사합니다.
  • { cache: "no-store" }:
    • 데이터를 캐싱하지 않습니다.
    • 요청이 있을 때마다 매번 새로운 데이터를 가져옵니다.
    • Next.js 15부터는 이 옵션이 fetch의 기본값입니다.
    • 페이지 라우터의 getServerSideProps와 유사합니다.
  • { next: { revalidate: 3 } }:
    • 3초마다 캐시를 업데이트합니다.
    • 페이지 라우터의 ISR(Incremental Static Regeneration)과 유사합니다.
  • { next: { tags: ['a'] } }:
    • 태그를 기반으로 캐시를 관리합니다.
    • 이 태그를 사용해 특정 시점에 캐시를 수동으로 갱신(On-Demand Revalidation)할 수 있습니다.

캐시 동작 확인하기

next.config.ts에서 fetch 로그를 확인할 수 있습니다.

import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  logging: {
    fetches: {
      fullUrl: true,
    }
  }
}

export default nextConfig

Request Memoization: 중복 요청 방지

하나의 페이지 렌더링 중 발생하는 중복된 API 요청을 자동으로 하나로 합쳐주는 기능입니다.

동작 방식

동일한 API를 3번 호출 → 실제로는 1번만 호출
MISS → SKIP → SET → HIT → HIT

데이터 캐시 vs Request Memoization

  • 데이터 캐시: 서버가 가동 중인 동안 영구적으로 보관
  • Request Memoization: 하나의 렌더링 사이클 동안만 중복 요청 방지
  • 데이터 캐시는 서버 인스턴스가 살아있는 동안 지속될 수 있는 반면, 리퀘스트 메모이제이션은 페이지 렌더링이 완료되면 캐시가 초기화되는 임시적인 캐시입니다. 목적과 생명 주기가 다릅니다.

캐시 옵션이 다른 동일 API 호출

중요한 포인트: 캐시 옵션이 다르면 완전히 다른 요청으로 취급됩니다.

// 이 두 요청은 서로 다른 요청으로 인식되어 각각 API 호출 발생
await fetch('/api/book', { cache: "no-store" })
await fetch('/api/book', { cache: "force-cache" })

Request Memoization이 적용되려면:

  • URL이 동일할 것
  • HTTP 메서드가 동일할 것
  • 요청 옵션(캐시 설정 포함)이 동일할 것

마치며

서버 컴포넌트의 도입으로 데이터 페칭 패턴이 완전히 변화했습니다. 이제는 데이터가 필요한 컴포넌트에서 직접 가져올 수 있어, 복잡한 props drilling이나 Context API 없이도 깔끔한 코드를 작성할 수 있습니다.

 

이 링크를 통해 구매하시면 제가 수익을 받을 수 있어요. 🤗

https://inf.run/4oB9v

반응형

'기술, 개발 > nextjs' 카테고리의 다른 글

8차 강의 노트 (스트리밍)  (3) 2025.08.28
7차 강의 노트 (페이지 캐싱)  (0) 2025.08.28
5차 강의 노트 (앱라우터)  (0) 2025.08.28
4차 강의 노트 (앱라우터)  (1) 2025.08.28
3차 강의 노트 (사전랜더링)  (2) 2025.08.28