[Next.js] Dynamic Routes ๋ค์ด๋๋ฏน ๋ผ์ฐํธ
TL;DR
[slug]
: ๋จ์ผ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ ํฌ์ฐฉ[...slug]
: ๋ค์ค ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ ํฌ์ฐฉ(Catch-All)[[...slug]]
: ๋ฃจํธ ๊ฒฝ๋ก๋ฅผ ํฌํจํ ๋ชจ๋ ๊ฒฝ๋ก๋ฅผ ์ ํ์ ์ผ๋ก ํฌ์ฐฉ(Optional Catch-All)
Dynamic Segments
์ ํํ ์ธ๊ทธ๋จผํธ ์ด๋ฆ์ ๋ฏธ๋ฆฌ ์ ์ ์์ ๋ ํด๋ ์ด๋ฆ์ ๋๊ดํธ๋ก ๊ฐ์ธ๋ฉด ๋ค์ด๋๋ฏน ์ธ๊ทธ๋จผํธ๋ก ์๋. ์ธ๊ทธ๋จผํธ ์ด๋ฆ์ layout, page ๋๋ route ํ์ผ์์ params
ํ๋กญ์ผ๋ก ๊ฐ ์กฐํ ๊ฐ๋ฅ.
Route | URL Example | Params |
app/blog/[slug]/page.js |
/blog/a |
{ slug: 'a' } |
app/blog/[slug]/page.js |
/blog/b |
{ slug: 'b' } |
๋ฃจํธ ๊ฒฝ๋ก(blog/)์ ํ์ด์ง ์์ผ๋ฉด ์ ๊ทผ ๋ถ๊ฐ.
Catch-all Segments
๋ค์ด๋๋ฏน ์ธ๊ทธ๋จผํธ๋ฅผ ํ์ฅํ์ฌ ๊ฒฝ๋ก์ ์ฌ๋ฌ ์ธ๊ทธ๋จผํธ๋ฅผ ํฌ์ฐฉํ๋ ค๋ฉด ํด๋ ์ด๋ฆ ์์ ์ 3๊ฐ(โฆ)๋ฅผ ์ถ๊ฐํ์ฌ Catch-All ์ธ๊ทธ๋จผํธ๋ก ์ค์ ๊ฐ๋ฅ. ์ด๋ฅผ ํตํด ์ฌ๋ฌ ๊ฒฝ๋ก๋ฅผ ํ๋์ ์ธ๊ทธ๋จผํธ๋ก ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ params
๋ ๋ฐฐ์ด ํํ๋ก ์ ๋ฌ๋จ.
Route | URL Example | Params |
app/blog/[...slug]/page.js |
/blog/a |
{ slug: ['a'] } |
app/blog/[...slug]/page.js |
/blog/a/b |
{ slug: ['a', 'b'] } |
๋ฃจํธ ๊ฒฝ๋ก(blog/)์ ํ์ด์ง ์์ผ๋ฉด ์ ๊ทผ ๋ถ๊ฐ.
Optional Catch-all Segments
Catch-All ์ธ๊ทธ๋จผํธ๋ฅผ ์ ํ์ ์ผ๋ก ์ ์ฉํ ๋ ๋๊ดํธ 2๊ฐ๋ฅผ ์ฌ์ฉํ์ฌ Optional Catch-All ์ธ๊ทธ๋จผํธ๋ก ์ค์ ๊ฐ๋ฅ. ๋ฃจํธ ๊ฒฝ๋ก์ ํ์ ๊ฒฝ๋ก๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํ ์ ์์ผ๋ฉฐ, ๋ฃจํธ ๊ฒฝ๋ก์์ params.slug
๊ฐ์ด undefined
๋ก ์ ๋ฌ๋จ.
Route | URL Example | Params |
app/blog/[[...slug]]/page.js |
/blog |
{ slug: undefined } |
app/blog/[[...slug]]/page.js |
/blog/a |
{ slug: ['a'] } |
app/blog/[[...slug]]/page.js |
/blog/a/b |
{ slug: ['a', 'b'] } |
๋ฃจํธ ๊ฒฝ๋ก(blog/)๋ก ์ ๊ทผํ๋ฉด app/blog/[[...slug]]/page.js
๋ก ๋งคํ๋จ.
โ ๏ธ Optional Catch-All ์ธ๊ทธ๋จผํธ ์ฌ์ฉ์ ๋์ผ ๋ฃจํธ ํด๋์ ๋ณ๋์ ํ์ด์ง ํ์ผ์ ์ถ๊ฐ ๋ชปํจ ๐ฆ app/ โโ blug/ โโ [[...slug]]/ โ โโ page.tsx โโ page.tsx (โ ๋ถ๊ฐ)
Generating Static Params
generateStaticParams
๋ฅผ ์ฌ์ฉํ๋ฉด ๋์ ๊ฒฝ๋ก ๊ธฐ๋ฐ์ ์ ์ ํ์ด์ง๋ฅผ ๋น๋ ํ์์ ๋ฏธ๋ฆฌ ์์ฑํ ์ ์์ผ๋ฉฐ, ์ด ํจ์ ์์์ fetch
๋ก ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ ์๋์ผ๋ก ๋ฉ๋ชจ์ด์ง๋๋ค. ์ดํ ๋ค๋ฅธ ํ์ด์ง๋ ๋ ์ด์์ ๋ฑ์์ ๋์ผํ arguments๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด๋ธ ์์ฒญ์ ์ถ๊ฐ์ ์ธ ๋คํธ์ํฌ ์์ฒญ ์์ด ๊ฐ์ ์ฌ์ฌ์ฉํ๋ค. ์ด๋ฅผ ํตํด ๋น๋ ์๊ฐ์ ํจ์จ์ ์ผ๋ก ๋จ์ถํ ์ ์๋ค.
export async function generateStaticParams() { // API ํธ์ถ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ๋ฑ์ผ๋ก ๋์ ๊ฒฝ๋ก ๋ชฉ๋ก์ ๊ฐ์ ธ์ด const posts = await fetch('https://api.example.com/posts').then((res) => res.json()); return posts.map((post) => ({ slug: post.slug, // slug๋ ๋์ ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ์ ํด๋น })); } export default function Page({ params }) { return <div>Post: {params.slug}</div>; }
๊ธ ์์ ์ฌํญ์ ๋ ธ์ ํ์ด์ง์ ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋ฐ์๋ฉ๋๋ค. ๋งํฌ๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์
'๐ช Programming' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[CSS] ์์ ๋งฅ๋ฝ Stacking Context (0) | 2025.02.26 |
---|---|
[React] ๋ฆฌ์กํธ 19 ์ ๋ฐ์ดํธ ๋ด์ฉ ํบ์๋ณด๊ธฐ (0) | 2025.02.08 |
[Next.js] App Router ๊ณต์ ํํ ๋ฆฌ์ผ ํบ์๋ณด๊ธฐ (1) | 2025.01.30 |
[Dev] ์๋งจํฑ ๋ฒ์ ๋ Semantic Versioning (0) | 2025.01.27 |
[React] ๋ฆฌ์กํธ์ ์ฌ๋ฐ๋ฅธ useEffect ์ฌ์ฉํ (2) | 2025.01.21 |
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋ค๋ฅธ ๊ธ
-
[CSS] ์์ ๋งฅ๋ฝ Stacking Context
[CSS] ์์ ๋งฅ๋ฝ Stacking Context
2025.02.26 -
[React] ๋ฆฌ์กํธ 19 ์ ๋ฐ์ดํธ ๋ด์ฉ ํบ์๋ณด๊ธฐ
[React] ๋ฆฌ์กํธ 19 ์ ๋ฐ์ดํธ ๋ด์ฉ ํบ์๋ณด๊ธฐ
2025.02.08 -
[Next.js] App Router ๊ณต์ ํํ ๋ฆฌ์ผ ํบ์๋ณด๊ธฐ
[Next.js] App Router ๊ณต์ ํํ ๋ฆฌ์ผ ํบ์๋ณด๊ธฐ
2025.01.30 -
[Dev] ์๋งจํฑ ๋ฒ์ ๋ Semantic Versioning
[Dev] ์๋งจํฑ ๋ฒ์ ๋ Semantic Versioning
2025.01.27
๋๊ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.