본문 바로가기
개발 기록장

[Next.js] Next.js 13에서 SSG, SSR, ISR 적용하기_fetch() API

by heereal 2023. 6. 10.

NEXT.JS 13 버전에서는 `getStaticProps`, `getServerSideProps` 함수를 더 이상 사용하지 않는다는 소식을 보고 그럼 SSR과 SSG는 어떻게 적용할 수 있는 걸까 궁금해서 찾아봤다.

 

일단 NEXT 13부터 모든 컴포넌트가 기본적으로 서버 컴포넌트로 동작하게 되었으며 SSR, SSG, ISR을 적용하기 위해서 

`getStaticProps`, `getServerSideProps` 등의 함수가 아닌 `fetch` API를 사용한다.

 

Data Fetching

// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });

// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });

// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });
The native fetch Web API has also been extended in React and Next.js. It automatically dedupes fetch requests and provides one flexible way to fetch, cache, and revalidate data at the component level. This means all the benefits of Static Site Generation (SSG), Server-Side Rendering (SSR), and Incremental Static Regeneration (ISR) are now available through one API

Next.js 13 공식문서를 확인하면 SSG, SSR, ISR 렌더링 방식을 `fetch Web API` 하나로 모두 설정할 수 있다고 한다. `fetch` API를 사용할 때 원하는 캐시 옵션을 설정하면 된다.

 

 

1. SSG (force-cache)

// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });
  • `getStaticProps`와 비슷한 옵션
  • `force-cache`는 fetch API를 사용할 때 기본값이며 생략 가능하다.
  • 처음에는 서버 렌더링 방식으로 작동하고 두 번째부터는 캐시 된 값을 불러온다.

 

2. SSR (no-store)

// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });
  • `getServerSideProps`와 비슷한 옵션
  • 매 요청 시마다 서버 사이드 렌더링 방식으로 작동한다.
  • 모든 요청에서 최신 데이터를 받아올 수 있다.

 

3. ISR (revalidate)

// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });
  • `revalidate` 옵션이 있는 `getStaticProps`와 비슷하다.
  • `revalidate` 설정 시간마다 캐시를 갱신한다.
  • `revalidate` 설정 시간 이후 해당 페이지에 대한 요청이 들어온다면 데이터를 refetch 하고 페이지를 재생성한다.

 


generateStaticParams()

export function generateStaticParams() {
  return [{ id: '1' }, { id: '2' }, { id: '3' }]
}
 
// Three versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
// - /product/1
// - /product/2
// - /product/3
export default function Page({ params }: { params: { id: string } }) {
  const { id } = params
  // ...
}
// Return a list of `params` to populate the [slug] dynamic segment
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
  }))
}
 
// Multiple versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
export default function Page({ params }) {
  const { slug } = params
  // ...
}
  • 기존 `getStaticPaths` 함수가 `generateStaticParams`로 대체되었다.
  • SSG를 적용할 때 `generateStaticParams`에 지정된 모든 경로(페이지)를 정적으로 미리 생성한다.

 


SSG 코드 예시

import React from 'react'

type Props = {
  params: {
    todoId: string,
  },
}

const fetchTodo = async (todoId: string) => {
  const res = await fetch(
    `https://jsonplaceholder.typicode.com/todos/${todoId}`,
    { cache: 'force-cache' },
  )
  const todo: TodoType = await res.json()
  return todo
}

async function TodoId({ params: { todoId } }: Props) {
  const todo = await fetchTodo(todoId)

  return (
    <div className='space-y-2 border-4 border-blue-400 bg-slate-300 p-2'>
      <div>Todo Id : {todoId}</div>
      <div>Todo Title : {todo.title}</div>
      <div className='border-t border-black py-2'>
        Completed :{todo.completed ? <span> Yes</span> : <span> No</span>}
      </div>
    </div>
  )
}

export default TodoId

export async function generateStaticParams() {
  const res = await fetch(`https://jsonplaceholder.typicode.com/todos/`)
  const todos: TodoType[] = await res.json()

  // [ { todoId: '1'}, {todoId: '2'}, ...{todoId: '200'}]
  return todos.map(todo => ({
    todoId: todo.id.toString(),
  }))
}
  • `generateStaticParams`로 todo.id를 params로 넘긴다.
  • TodoId 컴포넌트에서 params를 받고, fetch 함수를 실행할 때 params를 인자로 다시 넘긴다.
  • 데이터를 fetch할 때 인자로 받은 todoId를 이용해서 특정 todoId의 데이터만 fetch 한다.

 

import React from "react";
import { notFound } from "next/navigation";

...
...
...

async function TodoId({ params: { todoId } }: Props) {
  const todo = await fetchTodo(todoId);
  if (!todo.id) return notFound();

  return (
   ...
   ...
  );
}
  • 추가적으로 `generateStaticParams`에서 미리 동적으로 생성하지 않은 페이지에 접속했을 경우에 404 페이지로 이동하려면 Next.js에서 제공하는 notFound 컴포넌트를 이용한다.
  • /todos/[todoId] 디렉터리에 `not-found.tsx` 파일을 생성해야 한다.

 


참고 문서

 

Next.js 13

Next.js 13 introduces layouts, React Server Components, and streaming in the app directory, as well as Turbopack, an improved image component, and the brand new font component.

nextjs.org

 

Data Fetching: Fetching | Next.js

The Next.js App Router allows you to fetch data directly in your React components by marking the function as async and using await for the Promise. Data fetching is built on top of the fetch() Web API and React Server Components. When using fetch(), reques

nextjs.org

 

Functions: generateStaticParams | Next.js

Using App Router Features available in /app

nextjs.org

 

Next.js 13에서 SSG와 ISR 적용하기

Next.js 13에서 SSG와 ISR 적용하기, 그리고 not-found 컴포넌트 작성

mycodings.fly.dev

 

[Next.js] Next.js 13 - Data Fetching, Server Components

Data Fetching 13 이전까지 사용되었던 getServerSideProps와 getStaticProps는 이제 잊어라!!..는 아니고.. 13부터 도입된 방법이 앞으로 활발하게 사용되더라도, 레거시 코드에는 이 둘이 남아있을테니 아예

ahnanne.tistory.com

 

 

 

 

댓글