NextJS - 앱 라우터의 데이터 패칭

김명원·2025년 3월 20일

learnNextjs

목록 보기
19/24

앱 라우터의 데이터 패칭

기존의 Page Router에서는
오직 서버 측에서만 실행이 되는 함수들을
1. SSR(서버 사이드 렌더링)

export async function getServerSideProps(){
  return {props :{...}}
}
  1. SSG(정적 사이트 생성)
export async function getStaticProps(){
  return {props :{...}}
}
  1. Dynamic SSG(동적 경로에 대한 정적 사이트 생성)
export async function getStaticPaths(){
  return {paths : [...], fallback :...}
}

사용해 데이터를 받아와서
데이터 받아오는 것들은 페이지에서 props에서 받아왔습니다.
서버와 클라이언트 모두 실행이 되는 방법이 존재했습니다.
하지만

App Router 부터는 서버클라이언트가 따로 존재하기 때문에 페이지에 async와 fetch 메서드를 활용해서 데이터를 직접 불러오도록 하는 데이터 패칭 로직 작성해도 문제가 발생하지 않습니다.

그렇기에 App Router에서는 getServerSideProps(), getStaticProps(), getStaticPaths()를 사용하지 않고 컴포넌트 내부에서 직접 데이터를 불러와서 바로 렌더링에 사용할 수 있도록 데이터를 fetching하는 방법이 변경됩니다.

이제는 더이상 최상위 컴포넌트에서 데이터를 props나 context API를 활용해서 넘겨줄 필요 없이

해당하는 컴포넌트가 직접 데이터를 fetching을 하면되기 때문입니다.

공식 문서에서도 Fetching data where it's needed 이라고 제안하고 있습니다.

꿀팁 만약 env 파일에 API_SERVER_URL을 저장할시

만약 API_SERVER_URL을 .env파일에 저장하고 변수로 활용할 시
NEXT_PUBLIC을 붙여 NEXT_PUBLIC_API_SERVER_URL로 사용해야 합니다.
NEXT_PUBLIC을 붙이지 않는다면 서버 측에서만 사용하기 때문에 만약 클라이언트에서도 함께 이용을 해야 하는 환경 변수가 있다면 접두사를 꼭 붙여서 사용해야 합니다.

데이터 캐시(Data Cache)

데이터 캐시란? fetch 메서드를 활용해 불러온 데이터를 Next 서버에서 보관하는 기능을 말합니다.
영구적으로 데이터를 보관하거나, 특정 시간을 주기로 갱신 시키는 것도 가능합니다.
데이터 캐시는 불필요한 데이터 요청의 수를 줄여 웹 서비스의 성능을 크게 개선할 수 있는 장점이 존재합니다.

기존의 fetch 메서드에서 두번째 인자로서 cache를 적용할 수 있습니다.

위 처럼 cache의 옵션을 force-cache로 하게 되면 요청의 결과를 무조건 캐싱 되도록 설정이 됩니다.

캐시된 데이터를 계속 꺼내다 쓰게 됩니다.

다양한 옵션들이 존재합니다. 이 중 fetch 메서드만 사용 가능한 것들도 존재 합니다.

no-store

데이터 패칭의 결과를 저장하지 않는 옵션입니다.
즉, 캐싱을 아예 하지 않도록 설정하는 것입니다.

예를들어 기존의 데이터 패칭 옵션 함수가 있으면

async function AllBookcs() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`
  );
  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>;
  }
  const allBooks: BookData[] = await response.json();
}
async function AllBookcs() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`,
    { cache: "no-store" }
  );
  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>;
  }
  const allBooks: BookData[] = await response.json();
}

이렇게 적용하면 됩니다.
만약 로그로 확인하고 싶다면 next.config.ts 파일에 들어가

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  logging: {
    fetches: {
      fullUrl: true,
    },
  },
};

export default nextConfig;

똑같이 설정해주면 로그로 확인할 수 있습니다.
그러면 cache skip이라는 로그가 뜬것을 확인할 수 있습니다

 │ GET http://localhost:12345/book 200 in 88ms (cache skip)
 │ │ Cache skipped reason: (cache: no-store)
 │ GET http://localhost:12345/book/random 200 in 145ms (cache skip)
 │ │ Cache skipped reason: (auto no cache)

만약 아무것도 넣지 않는 함수가 존재하면 캐시 되지 않는 요청으로 동작을 하게 됩니다. 그게 auto no cache 로그가 뜨는 이유 입니다.

force-cache

no-store의 반대로 요청의 결과를 무조건 캐싱하며 한 번 호출 된 이후에는 다시는 호출되지 않습니다.

async function AllBookcs() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book`,
    { cache: "no-store" }
  );
  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>;
  }
  const allBooks: BookData[] = await response.json();
}

async function RecoBooks() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/random`,
    { cache: "force-cache" }
  );
  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>;
  }
  const recoBooks: BookData[] = await response.json();

}

이렇게 적용하면 로그에는

 │ GET http://localhost:12345/book/random 200 in 16ms (cache hit)
 │ GET http://localhost:12345/book 200 in 186ms (cache skip)
 │ │ Cache skipped reason: (cache: no-store)

cache hit로 잘 적용이 되는 것을 확인 가능합니다.

revalidate

특정 시간을 주기로 캐시를 업데이트 하는 과정이 마치 Page Routerㅇ의 ISR 방식과 유사한 방법입니다.

위와 같이 설정하면 데이터를 3초 주기로 Next 서버가 업데이트하게 됩니다.

async function RecoBooks() {
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/random`,
    { next: { revalidate: 3 } }
  );
  if (!response.ok) {
    return <div>오류가 발생했습니다...</div>;
  }
  const recoBooks: BookData[] = await response.json();

Next Tag

On-demand Revalidate라고 부르는 Next Tag 방식은 On-demand ISR 같은 방식으로 요청이 들어왔을 때 데이터를 최신화 하는 방법입니다.

데이터 패칭을 최적화 해주는 Request Memoization

Request Memoization이란 페이지를 서버 측에서 렌더링하는 과정에서 레이아웃 컴포넌트나 또는 페이지 컴포넌트처럼 하나의 페이지를 이루고 있는 여러 개의 컴포넌트에서 발생하는 다양한 API 요청들 중에 중복적으로 발생하는 요청들을 단 한 번만 요청할 수 있도록 자동으로 데이터 패칭을 최적화 해주는 기능입니다.

Request Memoization은 오직 중복된 API 요청을 방지하는 데에만 목적을 두고 있습니다. 데이터 캐시는 전혀 다른 것이다라고 기억을 해야합니다.

profile
개발자가 되고 싶은 정치학도생의 기술 블로그

0개의 댓글