[Next.js] Page Router - SSG

Yeonju·2025년 2월 21일

Next.js

목록 보기
9/10

SSG 페이지의 실행 순서

  1. getStaticProps 함수가 실행된다.
  2. 페이지 컴포넌트가 실행된다.
  3. 렌더링 완료 이후에 https://www.~ 페이지 요청이 온다.

개발 모드

개발 모드에서는 렌더링 방식이 SSG이더라도 새로고침 할 때마다 페이지를 새로 렌더링한다. (개발 편의를 위해)

프로덕션 모드

npm run build를 했는데

9:3  Error: 'description' is defined but never used.  @typescript-eslint/no-unused-vars
...

이런 에러가 뜬다면? eslint 설정을 바꿔주자

📌 .eslintrc.json 파일 설정

{
  "extends": ["next/core-web-vitals", "next/typescript"],
  "rules": {
    "no-unused-vars": "off",
    "@typescript-eslint/no-unused-vars": "off"
  }
}

"no-unused-vars": "off" : 사용하지 않는 변수가 있을 때, 경고나 오류 발생 X
"no-unused-vars": "warn" : 사용하지 않는 변수가 있을 때, 경고(warning)만 표시하고 오류 발생 X

📌 build 결과

...

○  (Static)   prerendered as static content
●  (SSG)      prerendered as static HTML (uses getStaticProps)
ƒ  (Dynamic)  server-rendered on demand

: 아무 설정이 없어서 기본적으로 SSG로 렌더링된 페이지
: getStaticProps를 사용해서 SSG로 설정한 페이지
ƒ : SSR로 설정한 페이지

사전 렌더링 결과물

.next/server/pages에서 확인할 수 있다.


정적 경로에 적용하기

getStaticProps

파일 내에 약속된 이름의 함수 getStaticProps 만들어 내보내면 (export), 해당 페이지는 SSG 방식이 적용된다.

return

return {
  props: {

  },
};

반드시 단 하나의 프로퍼티 props를 가지는 객체를 리턴해야한다.

페이지 컴포넌트

getStaticProps에서 리턴한 객체 props : 페이지 컴포넌트의 props로 받는다.

📌 InferGetStaticPropsType 타입

export default function Home({...}: InferGetStaticPropsType<typeof getStaticProps>) {

props는InferGetStaticPropsType<typeof getStaticProps> 타입으로 정의한다.
getStaticProps 반환값 타입을 자동으로 추론하는 타입이다.


동적 경로에 적용하기

상품 상세 페이지처럼 경로가 동적인 경우( /product/[id] 등)에는 어떤 경로가 존재하는지를 먼저 알려줘야한다.

  1. 경로 설정 : getStaticPaths
  2. 경로 개수만큼 페이지 렌더링 : getStaticProps

getStaticPaths

export const getStaticPaths = () => {
  return {
    paths: [
      // 가능한 경로들
    ],
    fallback: // 옵션 설정
  };
};

paths : 가능한 경로들을 배열로 반환
fallback : paths에 없는 경로를 요청할 경우 대비책

getStaticPaths, paths로 복수형으로 작성할 것.. 실수로 s 까먹으면 에러난다.

📌 paths 형식

paths: [
  { params: { id: "1" } },
  { params: { id: "2" } },
  { params: { id: "3" } },
  ...
],

경로 하나당 객체 형식으로 작성
number 타입 1 로 전달 X
string 타입 "1"로 전달해야 한다.

📌 fallback: false

  1. paths에 없는 페이지 요청이 온다.
  2. 404 not found 페이지 반환

📌 fallback: "blocking"

  1. paths에 없는 페이지 요청이 온다.
  2. SSR처럼 즉시 렌더링하여 페이지 제공
  3. 렌더링 결과물을 .next/server/page에 저장
  4. 이후 같은 요청이 오면, SSG처럼 이미 렌더링한(아까 저장해둔) 페이지 제공

📌 fallback: true

  1. paths에 없는 페이지 요청이 온다.
  2. 서버에서 getStaticProps 실행하지 않고 렌더링 → props 없는 페이지 반환
  3. 화면에 데이터가 없는 상태의 페이지 렌더링 → fallback 상태
  4. props 계산 후,props만 따로 반환 (데이터만 따로 보냄)
  5. 화면에 데이터가 있는 상태의 페이지 렌더링

fallback 상태

페이지 컴포넌트가 아직 서버로부터 데이터를 전달받지 못한 상태

const router = useRouter();
router.isFallback; // fallback 상태이면 true, 아니면 false를 반환한다.

따라서 이런 식으로 로딩 처리를 할 수 있다.

if (router.isFallback) {
  return "로딩중입니다.";
}

경로에 query가 들어가는 경우

상품 검색처럼 경로에 query가 들어가는 경우 (product?q=냉동 등)에 getStaticProps를 사용해서 SSG 설정을 하면 다음과 같이 에러가 뜬다.


getStaticPropsContext에는 query가 없기 때문이다.
query는 사용자 입력으로 주어지는거고, SSG는 페이지 요청이 오기도 전에 렌더링하는거니 당연하다..

꼭 SSG로 해야 한다면, getStaticProps 없이
리액트에서 사용하던 방식(useEffect, useRouter, useState)으로 코딩하면 된다.

getStaticProps, getServerSideProps 둘 다 없는 경우에는 SSG 방식으로 설정되기 때문이다.

export default function Page() {
  const [books, setBooks] = useState<BookData[]>([]);

  const router = useRouter();
  const q = router.query.q;

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

  useEffect(() => {
    if (q) {
      fetchSearchResult();
    }
  }, [q]);

  return (
    <div>
      {books.map((book) => (
        <BookItem key={book.id} {...book} />
      ))}
    </div>
  );
}
profile
햄스터와 개발을 좋아합니다.

0개의 댓글