Next.js의 SSG(Static Site Generation) 개념과 활용

2025. 3. 2. 23:10프론트엔드/Next JS

728x90

Next.js의 SSG(Static Site Generation) 개념과 활용

1. SSG(Static Site Generation)란?

**SSG(정적 사이트 생성)**는 Next.js에서 빌드 시(static generation) 미리 HTML을 생성하여 정적인 페이지를 제공하는 방식입니다.

📌 주요 특징

  • 빌드 시점에 HTML을 생성하므로, 빠른 페이지 로딩 속도를 제공함
  • 서버 요청 없이 즉시 렌더링되므로 SEO(검색 엔진 최적화)에 유리함
  • 데이터가 자주 변경되지 않는 정적인 페이지에 적합
  • 사용자가 페이지를 요청하기 전에 미리 렌더링되므로 서버 부하를 줄일 수 있음

📌 getStaticProps를 사용하면 SSG 방식으로 페이지를 생성할 수 있음.

export const getStaticProps = async () => {
  // 빌드 시 실행됨
};

2. getStaticProps를 활용한 도서 목록 페이지 생성

📌 예제: 정적인 도서 목록 페이지 생성

// pages/index.tsx
import SearchableLayout from "@/components/searchable-layout";
import style from "./index.module.css";
import { ReactNode } from "react";
import BookItem from "@/components/book-item";
import { InferGetStaticPropsType } from "next";
import fetchBooks from "@/lib/fetch-books";
import fetchRandomBooks from "@/lib/fetch-random-books";

// SSG를 사용하여 도서 데이터를 미리 가져옴
export const getStaticProps = async () => {
  console.log("인덱스 페이지 빌드 중...");

  // 두 개의 API 요청을 병렬 처리하여 데이터 가져오기
  const [allBooks, recoBooks] = await Promise.all([
    fetchBooks(),
    fetchRandomBooks(),
  ]);

  return {
    props: {
      allBooks,
      recoBooks,
    },
  };
};

export default function Home({
  allBooks,
  recoBooks,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return (
    <div className={style.container}>
      <section>
        <h3>지금 추천하는 도서</h3>
        {recoBooks.map((book) => (
          <BookItem key={book.id} {...book} />
        ))}
      </section>
      <section>
        <h3>등록된 모든 도서</h3>
        {allBooks.map((book) => (
          <BookItem key={book.id} {...book} />
        ))}
      </section>
    </div>
  );
}

// 페이지 전체 레이아웃 설정
Home.getLayout = (page: ReactNode) => {
  return <SearchableLayout>{page}</SearchableLayout>;
};

✅ 코드 설명

  1. getStaticProps에서 fetchBooks()와 fetchRandomBooks()를 사용해 도서 데이터를 가져옴.
  2. Promise.all()을 사용하여 병렬로 API 호출을 수행하여 성능을 최적화함.
  3. getStaticProps에서 반환한 props가 컴포넌트에 전달되어 정적인 HTML로 미리 렌더링됨.
  4. Home.getLayout을 사용하여 페이지 전체에 SearchableLayout을 적용.
  5. console.log("인덱스 페이지 빌드 중...")는 빌드 시점에만 실행됨.

3. SSG와 검색(Query String) 처리 문제

Q. 검색어(Query String)와 같은 동적 데이터를 어떻게 처리할까?

  • getStaticProps는 빌드 시점에 데이터를 가져오므로, 검색어(q)를 기반으로 데이터를 가져올 수 없음.
  • SSG에서는 쿼리 스트링을 직접 사용할 수 없기 때문에, 클라이언트 측에서 데이터를 가져와야 함.

📌 해결 방법: 클라이언트에서 API 요청하여 처리

// pages/search.tsx
import SearchableLayout from "@/components/searchable-layout";
import { useRouter } from "next/router";
import { ReactNode, useEffect, useState } from "react";
import BookItem from "@/components/book-item";
import fetchBooks from "@/lib/fetch-books";
import { BookData } from "@/types";

export default function Page() {
  const [books, setBooks] = useState<BookData[]>([]);
  const router = useRouter();
  const q = router.query.q; // URL에서 검색어 가져오기

  const fetchSearchResult = async () => {
    if (q) {
      const data = await fetchBooks(q as string);
      setBooks(data);
    }
  };

  // 검색어가 변경될 때마다 API 요청
  useEffect(() => {
    fetchSearchResult();
  }, [q]);

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

// 페이지 전체 레이아웃 설정
Page.getLayout = (page: ReactNode) => {
  return <SearchableLayout>{page}</SearchableLayout>;
};

✅ 코드 설명

  1. useRouter()를 사용하여 URL에서 검색어(q)를 가져옴.
  2. useEffect에서 fetchBooks(q)를 호출하여 검색 결과를 가져옴.
  3. getStaticProps 대신 클라이언트 측에서 데이터를 가져와 SSG 방식과 동적으로 데이터를 불러오는 방식을 결합.
  4. 검색어가 변경될 때(q가 변경될 때)마다 API 요청을 새로 보냄.

4. getStaticProps의 revalidate 옵션 활용 (ISR)

Next.js에서는 revalidate 옵션을 사용하여 일정 시간마다 정적 페이지를 재생성할 수 있음.
이를 Incremental Static Regeneration(ISR) 이라고 함.

📌 10초마다 데이터를 갱신하는 SSG 예제

export const getStaticProps = async () => {
  const allBooks = await fetchBooks();
  const recoBooks = await fetchRandomBooks();

  return {
    props: {
      allBooks,
      recoBooks,
    },
    revalidate: 10, // 10초마다 정적 페이지를 다시 생성
  };
};

✅ revalidate의 동작 방식

  • revalidate: 10을 설정하면 사용자가 페이지를 방문할 때마다 캐시된 페이지를 확인함.
  • 10초가 지나면 새로운 요청이 들어올 때 페이지를 다시 생성.
  • 기존의 SSG의 장점(빠른 로딩 속도)을 유지하면서 데이터가 업데이트되는 효과를 제공.

5. getServerSideProps와의 비교

비교 항목 getStaticProps (SSG) getServerSideProps (SSR)

실행 시점 빌드 시 요청 시마다 실행
로딩 속도 매우 빠름 (미리 생성된 정적 페이지 제공) 느림 (매번 서버에서 데이터를 가져옴)
데이터 변경 반영 빌드 시 고정 (ISR로 해결 가능) 항상 최신 데이터 반영
SEO 최적화 우수 (정적 HTML 제공) 우수
서버 부하 낮음 높음

🎯 결론

  • 변경되지 않는 정적 페이지는 getStaticProps를 사용하여 미리 렌더링하는 것이 좋음.
  • 검색어 등 동적인 데이터는 getStaticProps 대신 클라이언트에서 API 요청하여 처리해야 함.
  • 데이터가 자주 바뀌지만, 즉시 반영할 필요가 없다면 revalidate(ISR) 옵션을 사용하면 됨.
  • 항상 최신 데이터를 보여줘야 하는 경우 getServerSideProps(SSR) 방식이 더 적절함.

🚀 즉, SSG는 빠른 성능과 SEO 최적화를 위한 강력한 기능이며, 동적 데이터 처리는 클라이언트에서 보완하는 것이 좋다!

728x90