ํ ์ ํฌ๊ธฐ๋ก ์๋ผ๋จน๋ Next.js ํ์ต์ ๋ฆฌ์ฉ์ ๋๋ค.
2.13) SSG 1. ์๊ฐ ๋ฐ ์ค์ต
2.14) SSG 2. ์ ์ ๊ฒฝ๋ก์ ์ ์ฉํ๊ธฐ
2.15) SSG 3. ๋์ ๊ฒฝ๋ก์ ์ ์ฉํ๊ธฐ
2.16) SSG 4. ํด๋ฐฑ์ต์ ์ค์ ํ๊ธฐ
2.13 SSG 1. ์๊ฐ ๋ฐ ์ค์ต
SSR์ ์ฅ๋จ์
์ฅ์ : ๋ธ๋ผ์ฐ์ ์ ์ ์ ์์ฒญ์ด ๋ค์ด์ฌ ๋๋ง๋ค ์ฌ์ ๋ ๋๋ง ๊ณผ์ ์์ ๋ฐฑ์๋ ์๋ฒ์์ ์๋ก์ด ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ฉด์ ํ์ด์ง ๋ด๋ถ์ ๋ฐ์ดํฐ๋ฅผ ํญ์ ์ต์ ๋ฒ์ ์ผ๋ก ์ ์งํ ์ ์์
๋จ์ : ๋ฐ์ดํฐ ํ์นญ์ด ๋๋ฌด ๋๋ฆฌ๊ฒ ๋๋ฉด ์ฌ์ฉ์ ๊ฒฝํ์ด ์์ข์์ง๋ค.
SSG(์ ์ ์ฌ์ดํธ ์์ฑ)๋
SSR์ ๋จ์ ์ ํด๊ฒฐํ ์ ์๋ ์ฌ์ ๋ ๋๋ง ๋ฐฉ์.
๋น๋ ํ์์ ๋ฏธ๋ฆฌ ํ์ด์ง๋ฅผ ์ฌ์ ๋ ๋๋ง ํ๋ ๋ฐฉ๋ฒ(ํ์ด์ง๋ฅผ ๋ฏธ๋ฆฌ ๋ฑ ํ ๋ฒ ์์ฑํ๋ค)
SSG์ ์ฅ๋จ์
์ฅ์ : ์ฌ์ ๋ ๋๋ง ๊ณผ์ ์ ๋ง์ ์๊ฐ์ด ์์๋๋ ํ์ด์ง๋๋ผ๋, ๋น๋ ํ์์ ๋ฏธ๋ฆฌ ๋ค ๋ง๋ค์ด๋๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์์ ์์ฒญ์๋ ํญ์ ๋งค์ฐ ๋น ๋ฅธ ์๋๋ก ์๋ตํ ์ ์๋ค.
๋จ์ : ๋น๋ ํ์ ์ดํ์๋ ๋ค์๋ ํ์ด์ง๋ฅผ ์๋กญ๊ฒ ๋ ๋๋ง ํ์ง ์๋๋ค. ๋ฐ๋ผ์ ์ต์ ๋ฐ์ดํฐ๊ฐ ๋น ๋ฅด๊ฒ ๋ฐ์๋์ด์ผ ํ๋ ํ์ด์ง๋ค์์๋ SSG ๋ฐฉ์์ด ์ ํฉํ์ง ์๋ค.
2.14 SSG 2. ์ ์ ๊ฒฝ๋ก์ ์ ์ฉํ๊ธฐ
SSG ์ฌ์ฉํ๊ธฐ
export const getStaticProps = async () => {
console.log("์ธ๋ฑ์ค ํ์ด์ง");
const [allBooks, recoBooks] = await Promise.all([
fetchBooks(),
fetchRandomBooks(),
]);
return {
props: { allBooks, recoBooks },
};
};
export default function Home({
allBooks,
recoBooks,
}: InferGetStaticPropsType<typeof getStaticProps>) {
...
getStaticProps๋ก export ํด์ ์ฌ์ฉ๊ฐ๋ฅ
SSG ๋์ ํ์ธ
npm run dev ๊ฐ๋ฐ๋ชจ๋์์๋ ์์ ์ฌํญ์ด ๋ฐ๋ก ๋ณด์ด๊ธฐ ๋๋ฌธ์ SSG์ ๋์ ํ์ธ ๋ถ๊ฐ๋ฅ
npm run build๋ฅผ ํตํด ๋น๋ํด์ ์ํ ๊ฐ๋ฅ
Collecting page data : ์ ์ ํ์ด์ง ์์ฑ์ ์ํ ๋ฐ์ดํฐ ์์ง
Generating static pages : SSG๋ก ๋์ํ๋๋ก ์ค์ ํ ํ์ด์ง๋ค์ด ์์ฑ๋๊ณ ์๋ค๋ ์๋ฏธ
Route์์ ๋ณด์ฌ์ง๋ ๊ธฐํธ๋ค์ ํตํด SSG ํ์ด์ง์ธ์ง Dynamic ํ์ด์ง(SSR)์ธ์ง ๋๋ Static ํ์ด์ง์ธ์ง ์ ์ ์๋ค.
๋ค๋ง Static์ ๊ธฐ๋ณธ์ ์ผ๋ก SSG๋ก ๋์ํ๋ค.
npm run start๋ก ํ์ธํด๋ณด๋ฉด index ํ์ด์ง๋ ์์ฃผ ๋น ๋ฅธ ์๋๋ก ๋ ๋๋ง ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ฟผ๋ฆฌ์คํธ๋ง์ผ๋ก ๋ฐ์ดํฐ ๋ฐ์ ์ฌ ๋ SSG๋ก ๋์ํ๋๋ก ํ๊ธฐ ์ํด์
getStaticProps์์ ์ฟผ๋ฆฌ์คํธ๋ง์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํ๋ค.
๋ฐ๋ผ์ ์ด๋ ๊ฒ param์ผ๋ก ์ ์์๋ง๋ค ๋ค๋ฅธ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์์ผ ํ๋๊ฒฝ์ฐ, CSR๋ก ๋์ํ๋๋ก ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค.
getServerSideProps๋ getStaticProps๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ์ ์ผ๋ก SSG๋ก ๋์ํ๋ค.
import SearchableLayout from "@/components/searchable-layout";
import { ReactNode, useEffect, useState } from "react";
import BookItem from "@/components/book-item";
import fetchBooks from "@/lib/fetch-books";
import { useRouter } from "next/router";
import { BookData } from "@/types";
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>
);
}
Page.getLayout = (page: ReactNode) => {
return <SearchableLayout>{page}</SearchableLayout>;
};
๊ทธ๋ฌ๋ฉด SSG์ผ๋ก ๋ฐํ๋ ํ์ด์ง๋ ๊ฐ๋ฐ์๋๊ตฌ์ network ํญ์์ ํ์ธ ๊ฐ๋ฅํ๋ค. (์๋ก๊ณ ์นจ ํ์)
๊ทธ๋ ๋ค๋ฉด SSG๋ฅผ ํตํด ๋ฐํ๋ HTML์ ํ์ธํ ์ ์๊ณ , ๋ง์ดํธ ๋ ์ดํ์ ์ฟผ๋ฆฌ์คํธ๋ง์ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ํ์นญํ ์ ์๋ค.
2.15 SSG 3. ๋์ ๊ฒฝ๋ก์ ์ ์ฉํ๊ธฐ
๋์ ๊ฒฝ๋ก(Dynamic Path)๋?
book/[id].tsx ์ฒ๋ผ book/1, book/2, book/3 ๊ณผ ๊ฐ์ด ๋ค์ด๋๋ฏนํ ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ ํ์ด์ง๊ฐ ๋์ ๊ฒฝ๋ก๋ฅผ ๊ฐ๋ ํ์ด์ง์ด๋ค.
๋ฐ๋ผ์ ๋์ ๊ฒฝ๋ก๋ ๋ง ๊ทธ๋๋ก ๋ณํ๋ ๊ฒฝ๋ก๋ก, ํน์ URL์ ์ผ๋ถ๊ฐ ๋ฐ๋๋ ๊ฒ์ ์๋ฏธํ๋ค.
๋์ ๊ฒฝ๋ก๊ฐ SSG ๋ฐฉ์์ผ๋ก ๋์ํ๊ธฐ ์ํด ํ์ํ ๋ถ๋ถ(๊ฒฝ๋ก ์ค์ ํ๊ธฐ)
์๋ฒ๊ฐ ๋น๋ ํ์์ ๋์ ๊ฒฝ๋ก ํ์ด์ง์ ์ ์ ์ฌ์ดํธ๋ฅผ ์์ฑ(SSG)ํ๊ธฐ์ํด์๋ ๋์ ๊ฒฝ๋ก์ ๋ค์ด๊ฐ ์ ์๋ ํ์ด์ง๋ค์ ์์์ผ ํ๋ค.
์๋ฅผ ๋ค์ด, book/1, book/2, book/3์ด ์กด์ฌํ๋ค๋ฉด 1, 2, 3์ด ์กด์ฌํ๋ค๋ ๊ฒ์ ์์์ผ ํ๋ค๋ ๊ฒ์ด๋ค.
์ด๋ฌํ ๊ฒฝ๋ก ์ค์ ๊ณผ์ ์ getStaticPaths ํจ์๋ฅผ ์์ฑํจ์ผ๋ก์ ์ํํ ์ ์๋ค.
export const getStaticPaths = () => {
return {
paths: [
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
],
};
};
fallback
๋ง์ผ์ ์ํฉ์ ๋๋นํ๋ ๋๋น์ฑ ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
๋ฐ๋ผ์ ์ฐ๋ฆฌ๊ฐ ๊ฒฝ๋ก๋ฅผ ์ค์ ํ์ง ์์ ํ์ด์ง(ex. book/4)์ ๋ํด ๋๋นํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ๋ฉด ๋๋ค.
์ธ ๊ฐ์ง ์ต์ ์ด ์๋ค.
export const getStaticPaths = () => {
return {
paths: [
{ params: { id: "1" } },
{ params: { id: "2" } },
{ params: { id: "3" } },
],
fallback: false,
};
};
1. fallback : false
์กด์ฌํ์ง ์๋ ํ์ด์ง์ ๋ํด 404๋ฅผ ๋ณด์ฌ์ค๋ค.
2.16 Fallback ์ต์ ์ค์ ํ๊ธฐ
Fallback ์ต์ ์ธ ๊ฐ์ง
1. fallback : false
2. fallback : "blocking"
3. fallback : true
2. fallback : "blocking"
blocking ์ต์ ์ผ๋ก ์ค์ ํด๋์ผ๋ฉด StaticPath์ ๋ฏธ๋ฆฌ ์ค์ ํ์ง ์์ ํ์ด์ง๋ค์ SSR ๋ฐฉ์์ผ๋ก ํ์ด์ง๋ฅผ ์๋กญ๊ฒ ์์ฑํ๋ค.
SSR ๋ฐฉ์์ผ๋ก ์์ฑ๋ ํ์ด์ง ์ดํ์๋ SSG ๋ฐฉ์์ผ๋ก ํ์ด์ง๋ฅผ ์๋กญ๊ฒ ์์ฑํด์ ์ ์ฅ๋ ํ์ด์ง๋ฅผ ๋งค์ฐ ๋น ๋ฅด๊ฒ ๋ฐํํ ์ ์๋ค.
build ํ ๋ง๋ค์ด์ง .next/server/pages/book ๋ณด๋ฉด path๋ฅผ ์ง์ ํด๋์ ํ์ด์ง๋ค์ html ํ์ผ์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
path๋ฅผ ์ง์ ํด๋์ง ์์ book/4์ ๊ฐ์ ํ์ด์ง์ ์ ์ํ๋ฉด ํด๋น ๊ฒฝ๋ก์ 4.html์ด ์์ฑ๋๋ ๊ฒ์ ๋ณผ ์ ์๊ณ , ์ด ๋๋ฌธ์ ๋ค์ book/4์ ์ ๊ทผํ๋ฉด ๋น ๋ฅด๊ฒ ํ์ด์ง๊ฐ ๋ณด์ธ๋ค.
fallback = "blocking" ์ฃผ์ ์ฌํญ
Static Path์ ์กด์ฌํ์ง ์์๋ ํ์ด์ง๋ฅผ SSR ๋ฐฉ์์ผ๋ก ์๋กญ๊ฒ ์์ฑํ ๋ ๋ฐฑ์๋ ์๋ฒ์๊ฒ ์ถ๊ฐ์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํด์ผ ๋๋ค๊ฑฐ๋ ์ฌ์ ๋ ๋๋ง์ ํ๋ ์๊ฐ์ด ๊ธธ์ด์ง๊ฒ ๋๋ฉด ์ด ์๊ฐ ๋์์๋ ๋ธ๋ผ์ฐ์ ์๊ฒ ์๋ฌด๊ฒ๋ ์๋ตํ์ง ์๋๋ค.
๋ฐ๋ผ์ ํ์ด์ง์ ํฌ๊ธฐ์ ๋ฐ๋ผ ๊ฝค ์ค๋ ์๊ฐ์ ๊ธฐ๋ค๋ ค์ผ ํ๋ ๊ฒฝ์ฐ๋ ์๊ธด๋ค.
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ถ์ ๋ fallback = true๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
3. fallback = true
๋ธ๋ผ์ฐ์ ๋ก๋ถํฐ ์กด์ฌํ์ง ์๋ ํ์ด์ง๋ฅผ ์์ฒญ ๋ฐ์์ ๋ props(getStaticProps๊ฐ ๋ฐํํ๋ props)๊ฐ ์๋ ๋ฒ์ ์ ํ์ด์ง๋ฅผ ๋จผ์ ๋น ๋ฅด๊ฒ ์์ฑํด์ ๋ธ๋ผ์ฐ์ ์๊ฒ ๋ฐํํ๋ค.
ํ์์ผ๋ก ์ด ํ์ด์ง์ ํ์ํ ๋ฐ์ดํฐ์ธ props๋ง ๋ฐ๋ก ๊ณ์ฐํด์ ๋ณด๋ด์ค๋ค.
fallback ์ํ์ผ ๋๋ง ๋์ฐ๊ณ ์ถ์ ํ์ด์ง๊ฐ ์๋ ๊ฒฝ์ฐ
export default function Page({
book,
}: InferGetStaticPropsType<typeof getStaticProps>) {
const router = useRouter();
if (router.isFallback) {
return "๋ก๋ฉ์ค์
๋๋ค.";
}
...
๋ฐ์ดํฐ๊ฐ ์์ ๋ ์กด์ฌํ์ง ์์ ํ์ด์ง๋ก ๋๊ธฐ๊ณ ์ถ๋ค๋ฉด
export const getStaticProps = async (context: GetStaticPropsContext) => {
const id = context.params!.id;
const book = await fetchOneBook(Number(id));
if (!book) {
return {
notFound: true,
};
}
return {
props: { book },
};
};
getStaticProps์์ return notFound๋ฅผ ํด์ฃผ๋ฉด ๋๋ค.
'FE > Next.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Next.js] Page Router ์ฅ๋จ์ (0) | 2025.05.06 |
---|---|
[Next.js] Page Router - ISR (4) | 2025.05.06 |
[Next.js] page router - SSR (3) | 2025.05.05 |
[Next.js] page router ์ฌ์ ๋ ๋๋ง๊ณผ ๋ฐ์ดํฐํ์นญ (0) | 2025.05.05 |
[Next.js] page router ํ์ด์ง๋ณ ๋ ์ด์์ ์ค์ (1) | 2025.05.03 |