On-Demand ISR(Incremental Static Regeneration on demand)
기능은 Nextjs에서 제공하는 강력한 렌더링 방식으로, 사용자 요청이 있을 때마다 정적 페이지를 다시 생성하여 최신 데이터를 반영하는 방법이다.
이전에 살펴본 ISR 방식은 일정 시간 간격으로 페이지를 갱신한다. 예를 들어, 60초마다 페이지를 갱신하도록 설정했다면 사용자가 이 페이지를 요청할 때마다 갱신 주기가 완료되지 않는 한 기존 페이지가 반환된다. 이 방식은 SSG 방식처럼 빠르게 응답할 수 있는 장점과, 특정 시간 간격으로 최신 데이터를 반영할 수 있는 SSR 방식의 장점을 결합한 최적화된 방법이다.
하지만 ISR은 시간이 아닌 사용자의 특정 행동에 따라 페이지를 갱신할 필요가 있는 경우에 불필요하거나 시의적절하지 않게 작동할 수 있다. 예를 들어, 커뮤니티 게시글 페이지에서 ISR을 60초 간격으로 설정했을 때, 사용자가 즉각적으로 게시글을 수정하거나 삭제했더라도 60초가 되기 전까지는 업데이트된 게시글을 볼 수 없게 된다. 또한 필요 없는 주기적 갱신이 계속 발생할 수 있다.
이때, On-Demand ISR
을 활용하면 사용자 요청을 받을 때마다 페이지를 재생성하도록 설정하여 페이지 갱신을 정확하고 효율적으로 수행할 수 있다.
이런 On-Demand ISR
방식을 이용하면, 앞서 살펴본 예시에서 시간을 기반으로 불필요하거나 또는 너무 늦게 페이지를 재생성하는 이러한 과정들은 싹 다 제거하고 실제로 사용자가 이 게시글을 수정해서 페이지에 데이터 업데이트가 진짜 필요해 졌을 때 Next서버에게 우리가 직접 페이지를 재생성 하라는 요청인 페이지 revalidate요청을 보내서 이 페이지를 이때 다시 생성하도록 설정해 줄 수 있다.
그러니까 쉽게 말하면, 이 방식은 이 페이지의 업데이트를 우리가 직접 트리거링 할 수 있다는 얘기가 되는 것이다. 그래서 이런 On Demand ISR이라는 새로운 방식의 ISR까지 이용하면 거의 대부분의 페이지를 최신 데이터를 반영하면서도 정적 페이지로써 처리해줄 수 있다.
사용자의 요청에 따라 인덱스 페이지를 재생성하는 On-Demand ISR을 설정해보자.
revalidate
주기를 제거하여 인덱스 페이지를 기본적인 SSG로 설정한다.
// src/pages/index.tsx
export const getStaticProps = async () => {
const [allBooks, recoBooks] = await Promise.all([
fetchBooks(),
fetchRandomBooks()
]); // 동시에 병렬 작동
return {
props: {
allBooks,
recoBooks
},
};
};
pages/api
폴더에 revalidate.ts
파일을 생성하고, API 라우트 핸들러
를 작성한다. 이 API 라우트는 재생성 요청을 받아 인덱스 페이지를 재생성한다.
// src/pages/api/revalidate.ts
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
await res.revalidate("/"); // 인덱스 페이지 경로 설정
return res.json({ revalidate: true });
} catch (err) {
res.status(500).send("Revalidation Failed");
}
}
revalidate
: res.revalidate()
메서드를 사용하여 페이지 재생성을 요청한다. 이 메서드에 어떤 페이지를 revalidate
시키려고 하는지 인수로 경로를 넣어주면 된다. 인덱스 페이지의 경로를 전달하면 요청이 들어올 때마다 해당 경로를 재생성한다.
그리고 나서 이 요청이 혹시나 실패할 수도 있으니까 try catch
블록으로 감싸주고, 요청이 성공했다는 가정 하에 res의 json으로 revalidate라는 프로퍼티를 true로 설정해서 index 페이지의 재생성이 잘 완료가 되었다고 응답을 해주도록 한다.
오류 처리
: 페이지 재생성이 실패할 경우, 상태 코드 500
을 반환하고 "Revalidation Failed"
메시지를 응답한다.
그럼 이제 이 api의 revalidate 주소로 접속 요청을 보내면, 이 handler가 실행이 된다. 그럼 response객체의 revalidate
메서드가 호출이 되어서 인수로 전달한 index
경로를 다시 생성하게 될 것이다. 그리고 페이지의 재생성이 성공 했다면, revalidate:true
라는 응답이 돌아오게 된다.
설정이 완료되면 프로젝트를 빌드하고 npm run start
로 애플리케이션을 실행한다.
localhost:3000
으로 접속하여 인덱스 페이지가 SSG 방식으로 렌더링되었는지 확인한다. 이때에는 새로고침을 계속 해도 SSG 방식으로 동작하기 때문에 데이터가 변화하지 않는다.
새로운 탭에서 localhost:3000/api/revalidate
로 접근하여 API 라우트
를 호출한다. 성공적으로 호출되면 { "revalidate": true }
JSON 응답이 나타난다.
이후 인덱스 페이지로 돌아가 새로고침을 해보면, 추천 도서 목록이 새롭게 갱신된 것을 확인할 수 있다.
이 과정은, revalidate API Routes로 요청을 보내서 index페이지를 On-Demand ISR 방식으로 다시 생성을 한 것이다.
On-Demand ISR
은 주기적인 갱신을 필요로 하지 않으면서도 사용자 행동에 따라 최신 데이터를 반영해야 하는 페이지에서 특히 유용하다. 예를 들어, 커뮤니티 게시글, 실시간 재고 목록, 이벤트 예약 현황 등 데이터 변경이 사용자의 행동에 따라 발생하는 경우에 적합하다. 또한, 필요한 순간에만 페이지를 재생성하므로 SSR 방식보다 서버 부하를 줄일 수 있다.
On-Demand ISR
을 통해 사용자는 항상 최신 데이터를 반영한 정적 페이지를 볼 수 있으며, 요청 시에만 재생성하므로 서버 효율성을 극대화할 수 있다. Next.js를 통해 최적화된 웹 애플리케이션을 구축할 때, 상황에 따라 On-Demand ISR
을 적극 활용하면 웹 성능과 데이터 갱신 속도를 크게 향상할 수 있다.