[Next.js] Page Router - ISR

Yeonju·2025년 2월 24일

Next.js

목록 보기
10/10

ISR (Incremental Static Regeneration)

실행 순서

  1. getStaticProps 함수가 실행된다.
  2. 페이지 컴포넌트가 실행된다.
  3. 페이지 요청(https://www.~) → 만들어둔 페이지를 반환한다.
  4. 설정한 시간(revalidate)이 지남 + 페이지 요청(https://www.~)이 다시 들어옴 → 다시 렌더링(1~2번 과정)
  5. 새로 만든 페이지를 반환한다.

설정하기

export const getStaticProps = async () => {
  return {
    props: {
		...
    },
    revalidate: 60,
  };
};

📌 revalidate

getStaticProps 함수가 리턴할 객체에 revalidate 프로퍼티를 추가하면 ISR 방식으로 렌더링된다.

프로퍼티의 값은 단위이다. 60을 입력하면 60초마다 페이지를 다시 렌더링하는 것이다.

📌 build 결과

...
✓ Collecting build traces    
✓ Finalizing page optimization

Route (pages)                             Size     First Load JS
┌ ● / (ISR: 3 Seconds) (334 ms)           1.05 kB        81.7 kB
├   └ css/37a00a8bb8b3801f.css            369 B
├   /_app                                 0 B            80.7 kB
├ ○ /404                                  311 B            81 kB
├ ƒ /api/hello                            0 B            80.7 kB
...

● /경로 (ISR: N Seconds) : N초 주기로 ISR 설정한 페이지 (예시에서 /만 있는 이유는 index라서)

📌 실행 결과

  ▲ Next.js 14.2.23
  - Local:        http://localhost:3000

 ✓ Starting...
 ✓ Ready in 690ms
index.tsx - getStaticProps 실행 	// 최초 빌드시 실행
index.tsx - getStaticProps 실행 	// 60초가 지난 후 새로운 요청 발생 → getStaticProps 실행
  1. 새로고침을 아무리 많이 눌러도, 설정한 시간이 지나기 전에는 index.tsx - getStaticProps 실행 로그가 남지 않는다.
  2. 하지만 설정한 시간이 지나도, 새로고침을 하지 않으면 index.tsx - getStaticProps 실행 로그가 남지 않는다. 즉, 요청이 없으면 페이지를 새로 렌더링하지는 않는다.

ISR을 적용하기 어려운 경우

시간과 관계 없이, 사용자의 행동에 따라 데이터가 업데이트되는 페이지의 경우이다.

예를 들어, 커뮤니티 사이트의 게시글 페이지를 생각해보면, 누군가 글을 올리거나 수정했는데도 설정한 시간이 지나지 않으면 페이지가 다시 생성되지 않는다. 반대로 시간 내에 아무도 글을 올리거나 수정하지 않았는데도 누군가 해당 페이지를 재요청하면 페이지를 다시 생성한다. (불필요한 페이지 재생성)


주문형 재검증 (On-Demand-ISR)

요청을 받을 때마다 페이지를 다시 생성하는 ISR

실행 순서

  1. getStaticProps 함수가 실행된다.
  2. 페이지 컴포넌트가 실행된다.
  3. 페이지 요청(https://www.~) → 만들어둔 페이지를 반환한다.
  4. 특정 API 요청 → 특정 페이지를 다시 렌더링(1~2번 과정)
  5. 페이지 요청(https://www.~) → 새로 만든 페이지를 반환한다.

ISR은 지정한 시간이 지나고, 새로운 요청까지 와야 재생성하지만 On-Demand-ISRAPI 요청이 오면 페이지 요청이 오지 않아도 즉시 페이지를 재생성한다.

설정하기

📌 pages/api/revalidate.ts

import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const { path } = req.body; // 요청에서 revalidate할 경로 받기

    if (!path) {
      return res.status(400).json({ message: "Path is required" });
    }

    await res.revalidate(path); // 해당 경로만 다시 렌더링

    return res.json({ message: `Revalidated ${path}` });
  } catch (error) {
    return res.status(500).json({ message: "Revalidation Failed" });
  }
}

revalidate API가 호출된 경우 실행될 로직을 구현한다.
req.body에 저장된 path를 받아 해당 경로만 다시 revalidate 하도록 한다.

📌 pages/api/myapi.ts

import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  // myapi 로직

  try {  
    const path = `/ISR 재검증할 경로`;

    // revalidate API 호출
    await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/revalidate`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ path }),
    });

    return res.json({ message: `Revalidated ${path}` });
  } catch (error) {
    return res.status(500).json({ message: "Revalidation Failed" });
  }
}

api 요청 로직을 수행한 후, revalidate API를 호출한다.

profile
햄스터와 개발을 좋아합니다.

0개의 댓글