動態路由
商品頁、文章頁這類網址常常帶著一個會變動的識別碼,例如 /products/42 或 /blog/hello-world。Next.js 用方括號資料夾名稱表示這種「會變動的路徑區段」,不用為每一種可能的值各寫一個頁面。
基本用法
方括號裡的名稱會變成 params 物件的欄位,在頁面元件裡可以直接取用:
app/products/[id]/page.tsx
export default async function ProductPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
return <h1>商品編號:{id}</h1>;
}
params 是 Promise
Next.js 15 起,params(與 searchParams)改為非同步,需要 await 才能取得實際內容;沿用舊版寫法(直接當物件用)在建置時會出現警告。
三種區段語法
| 語法 | 範例路徑 | 說明 |
|---|---|---|
[id] |
/products/42 |
剛好一段、必填的動態區段。 |
[...slug] |
/docs/a/b/c |
Catch-all,把剩下所有區段收進一個陣列,且至少要有一段。 |
[[...slug]] |
/docs、/docs/a/b |
可選的 catch-all,連完全沒有子路徑(只到 /docs)都會符合。 |
Catch-all 的 params 會是陣列,例如 /docs/a/b/c 對應到 { slug: ['a', 'b', 'c'] }。
搭配 generateStaticParams 預先產生頁面
如果動態頁面的內容在建置時就能知道所有可能的值(例如部落格文章清單),可以用 generateStaticParams 讓 Next.js 在建置階段就把每個頁面預先產生成靜態 HTML,兼顧動態路由的彈性與靜態頁面的效能:
app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map((post) => ({ slug: post.slug }));
}
export default async function BlogPost({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug);
return <article>{post.title}</article>;
}
沒有列在 generateStaticParams 回傳結果裡的路徑,預設仍會在第一次被造訪時動態渲染。
下一步
會建立路徑之後,接著看使用者如何在頁面之間移動,詳見 導覽與連結。