웹 애플리케이션의 렌더링 방식과 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,
};
};
fallbackfalse: 지정되지 않은 경로는 404 페이지를 반환"blocking": SSR처럼 즉시 생성true: 즉시 생성 + 페이지만 미리 반환
fallback: true 동작 및 로딩 상태 처리
fallback: true로 설정하면, getStaticPaths에서 반환되지 않은 경로에 대해 다음과 같이 동작한다.
- 처음에는 페이지의 "fallback" 버전을 즉시 표시한다.
- 백그라운드에서 Next.js가 요청된 경로에 대해 HTML과 JSON을 적정으로 생성한다.
- 생성이 완료되면, 브라우저는 생성된 페이지의 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 |
