Next.js 페이지 라우터의 렌더링 방식

Frontend/Next.js
 

웹 애플리케이션의 렌더링 방식과 Next.js

웹 애플리케이션을 개발할 때 가장 중요한 선택 중 하나는 렌더링 방식이다.각 방식은 고유한 장단점을 가지고 있으며, Next.js를 통해 이러한 방식들을 유연하게 활용할 수 있다.렌더링 방식CSR (C

devmark.tistory.com


서버 사이드 렌더링 (SSR)

요청이 들어올 때마다 사전 렌더링을 진행하는 방식

getServerSideProps

커포넌트보다 먼저 실행되어서 컴포넌트에 필요한 데이터를 불러오는 함수

export const getServerSideProps = () => {
  const data = "hello";

  return {
    props: {
      data,
    },
  };
};
export default function Page({ 
  data, 
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
  {* hello *}
  return <h1>{data}</h1>;
}

 

쿼리 스트링 접근

getServerSideProps 함수는 서버 사이드 렌더링 시 실행되며, context 객체를 통해 다양한 요청 정보에 접근할 수 있다.

'/serch?q=리액트'
export const getServerSideProps = async (
  context: GetServerSidePropsContext
) => {
  const { q } = context.query;
  console.log(q); // 리액트
};

 

정적 사이트 생성 (SSG)

빌드 타임에 미리 페이지를 사전 렌더링 해 두는 방식

getStaticProps

빌드 시점에 실행되어 정적 페이지를 생성하는 함수

export const getStaticProps = () => {
  const data = "hello";

  return {
    props: {
      data,
    },
  };
};
export default function Page({ 
  data, 
}: InferGetStaticPropsType<typeof getStaticProps>) {
  {* hello *}
  return <h1>{data}</h1>;
}

 

정적 경로에 적용

클라이언트 사이드 데이터 페칭

빌드 타임에 데이터를 미리 불러올 수 없는 경우 (예: 쿼리 스트링을 이용한 검색 페이지), 기존 리액트 앱에서 사용하던 방식으로 클라이언트 측에서 직접 데이터를 페칭할 수 있다.

export default function Page() {
  const [books, setBooks] = useState<BookData[]>([]);
  const router = useRouter();
  const { q } = router.query;

  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>
  );
}

 

동적 경로에 적용

getStaticPaths

동적 라우팅을 사용하는 페이지에서 어떤 경로를 사전 렌더링할지 정의한다.

// '/book/1', '/book/2', '/book/3' 경로 지정

export const getStaticPaths = async () => {
  return {
    paths: [
      { params: { id: "1" } },
      { params: { id: "2" } },
      { params: { id: "3" } },
    ],
    fallback: true,
  };
};
  • fallback
    • false: 지정되지 않은 경로는 404 페이지를 반환
    • "blocking": SSR처럼 즉시 생성
    • true: 즉시 생성 + 페이지만 미리 반환

 

fallback: true 동작 및 로딩 상태 처리

fallback: true로 설정하면, getStaticPaths에서 반환되지 않은 경로에 대해 다음과 같이 동작한다.

  1. 처음에는 페이지의 "fallback" 버전을 즉시 표시한다.
  2. 백그라운드에서 Next.js가 요청된 경로에 대해 HTML과 JSON을 적정으로 생성한다.
  3. 생성이 완료되면, 브라우저는 생성된 페이지의 JSON을 받아 올바른 데이터로 페이지를 렌더링한다.

이때 router.isFallback을 사용하여 페이지가 fallback 상태인지 확인하고, 적절한 로딩 UI를 표시할 수 있다.

import { useRouter } from 'next/router';

export default function Book({ book }) {
  const router = useRouter();

  if (router.isFallback) return <div>로딩 중입니다...</div>

  if (!book) {
    return <div>문제가 발생했습니다. 다시 시도해주세요.</div>
  }

  return (
    <div>
      <h1>{book.title}</h1>
      <p>{book.description}</p>
    </div>
  );
}

 

getStaticProps에서 notFound 사용하기

동적으로 생성되는 페이지에서 특정 조건에 따라 404 응답을 반환하고 싶을 때 유용하다.

export const getStaticProps = async (context: GetStaticPropsContext) => {
  const { id } = context.params!;
  const book = await fetchOneBook(Number(id));

  // 존재하지 않는 100번 데이터의 경로 '/book/100'는 404 페이지를 반환
  if (!book) {
    return {
      notFound: true,
    };
  }

  return {
    props: {
      book,
    },
  };
};

 

증분 정적 재생성 (ISR)

SSG 방식으로 생성된 정적 페이지를 일정 시간을 주기로 다시 생성하는 방식

revalidate 옵션

export const getStaticProps = async () => {  
  const [allBooks, recoBooks] = await Promise.all([
    fetchBooks(),
    fetchRandomBooks(),
  ]);

  return {
    props: {
      allBooks,
      recoBooks,
    },
    revalidate: 3, // 3초마다 페이지 재생성
  };
};

 

On-Demand ISR

시간 기반이 아닌, 요청을 기반으로 페이지를 다시 생성하는 ISR 방식


구현 방법 예시

// 정적 페이지 설정
export const getStaticProps = async () => {
  const [allBooks, recoBooks] = await Promise.all([
    fetchBooks(),
    fetchRandomBooks(),
  ]);

  return {
    props: {
      allBooks,
      recoBooks,
    },
  };
};
// revalidation API 엔드포인트 생성 (/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");
  }
}
  • 일반적인 새로고침으로는 데이터가 변경되지 않음
  • /api/revalidate 엔드포인트에 접속하면 페이지가 재생성됨
  • 재생성 후 페이지를 새로고침하면 데이터가 업데이트 됨

'Frontend > Next.js' 카테고리의 다른 글

React Server Component  (0) 2025.11.13
Next.js 검색 엔진 최적화 (SEO)  (0) 2025.11.13
Next.js의 프리 페칭 (Pre-fetching)  (0) 2025.11.13
Next.js의 레이아웃 설정  (0) 2025.11.09
Next.js의 네비게이팅  (0) 2025.11.09
'Frontend/Next.js' 카테고리의 다른 글
  • React Server Component
  • Next.js 검색 엔진 최적화 (SEO)
  • Next.js의 프리 페칭 (Pre-fetching)
  • Next.js의 레이아웃 설정
고견
고견
개발 자국 남기기
  • 고견
    개발자국
    고견
  • 전체
    오늘
    어제
    • 분류 전체보기 (157) N
      • Frontend (29)
        • Next.js (16)
        • JavaScript (7)
      • CS (19) N
        • 자료구조 (9)
        • 알고리즘 (5)
        • 운영체제 (4) N
        • 네트워크 (1) N
      • TIL (93)
      • Dev Log (16)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    memory
    cs50
    페이지 라우터
    Next.js
    바닐라 자바스크립트
    인터페이스
    C
    트러블 슈팅
    타입 좁히기
    함수 타입
    문자열
    ai 감성 일기장
    typescript
    Trouble Shooting
    algorithm
    Pages Router
    App Router
    react
    useState
    배열
    generic
    CS
    javascript
    알고리즘
    Spa
    클래스
    제네릭
    emotion diary
    앱 라우터
    자료구조
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
고견
Next.js 페이지 라우터의 렌더링 방식
상단으로

티스토리툴바