繼上一篇介紹 App Router,我們知道要怎麼在 App Router 中利用保留字建立路由及其他功能型組件,也了解了這些功能型組件是怎麼嵌套的。
接下來我們會介紹如何在 App Router 建立動態路由(dynamic router)。
當我們事先不能預知 router 的路徑是什麼,或者我們的頁面需要保持路徑的格式不變,但頁面會根據路由中的某一段進行渲染,這時候我們就可以使用動態路。
現在你看到的鐵人賽網站就是使用動態路由做渲染的,這篇 Day6 - App Router 動態路由 文章的路徑如下:
https://ithelp.ithome.com.tw/articles/10324542
如果你點擊其他的鐵人賽文章,你會看到前面這段路徑 https://ithelp.ithome.com.tw/articles/
還是一樣的,不過後面的路徑不是 10324542
,而是其他唯一值。這個唯一值是「IT邦幫忙」自動幫我生成的,用來確保每一頁都是獨一無二的,他們可以透過這個唯一值去找到對應的文章。
動態路由與固定路由的寫法很像,差別是檔案名稱需要用中括號包住。
我們以建立一個「it邦幫忙」的文章動態路由為例:
建立 app/articles/[slug]/page.tsx
,此時我們就建立好 /articles/[可填入任意參數]
的路由。接下來我們還需要根據 slug 參數去 fetch 文章的資料回來。我們可以從 page.tsx
的參數解構出 params
物件取得 slug 的值,注意這邊的 slug 是根據你檔案夾名稱而定,如果是 app/articles/[id]/page.tsx
,那就是取 id 值。
// app/articles/[slug]/page.tsx
type Props = {
params: { slug: string }
}
export default function Page({ params }: Props) {
// fetch article here
return <div>My Post: {params.slug}</div>
}
有時我們的動態路由挖空的參數不只一個怎麼辦?假設我們還多塞了些參數,並且這些參數是被允許的,像是
/articles/123
/articles/123/is-cool
/articles/123/is/very/long/but/still/work
。沒關係,你的煩惱,Next 知道。我們只要在檔案夾名稱加上展開運算符就可以,取得的 slug。
一樣以鐵人賽文章為例,該檔案路徑就是 app/articles/[...slug]/page.tsx
,此時從 page.tsx
取得的就是一個字串陣列,以上面的路徑為例,取得的 slug 值就會是
路徑 | slug值 |
---|---|
/articles/123 |
['123'] |
/articles/123/is-cool |
['123', 'is-cool'] |
/articles/123/is/very/long/but/still/work |
['123', 'is', 'very', 'long', 'but', 'still', 'work'] |
不知道大家有沒有注意到,上面的路由是不會配對到 /articles
本身,如果希望這個 page.tsx
也可以配對到 /articles
,那可以使用二維展開運算 slug (名字我取的,在官網找不到)。
一樣以鐵人賽路由為例,那就會是 app/articles/[[...slug]]/page.tsx
,這樣就可以連 /articles
也配對到了。
上面還有一種情境沒有講到,那就是有限個動態路由路由的情況。
這種情況會使用 SSG 的方法來達成目的:
還是以鐵人賽文章為例,我就只要渲染 slug 為 A, B, C 的鐵人賽文章,其他都不要渲染。
舉例:
我們可以在 app/articles/[slug].tsx
中 export 一個特殊的 function generateStaticParams
,這個 function name 也是 Next 的保留字,代表這個頁面要使用 SSG 渲染,它會在 build time 的時候執行這個 function 取得所有已知的 slug,並提前先把頁面的 html 給組好。
再透過 dynamicParams 決定是否允許以外的路徑訪問。
generateStaticParams 也可以使用非同步的方式取得 slug,這裡為了方便就直接寫死。
// 決定允不允許非 generateStaticParams 產出的 slug 訪問
export const dynamicParams = false // true | false,
export function generateStaticParams() {
const articles = ['A', 'B', 'C'];
return posts.map((post) => ({
slug: articles
}))
}
關於 dynamic 結合 SSG 的寫法,後面會再提到。
無力