使用情境
當在某一個路徑底下, 有共用的Layout, 透過不同的route path 渲染出不同的資料內容時, 可以透過Dynamic Routes 來處理這樣的情境.
單一子路徑
Route Example URL params
Router | Example URL | params
-------------------------------------------------
pages/blog/[slug].js | /blog/a | { slug: 'a' }
pages/blog/[slug].js | /blog/b | { slug: 'b' }
pages/blog/[slug].js | /blog/c | { slug: 'c' }
多階層子路徑
Catch-all Segment
Router | Example | URL params
-----------------------------------------------------------------
pages/shop/[...slug].js | /shop/a | { slug: ['a'] }
pages/shop/[...slug].js | /shop/a/b | { slug: ['a', 'b'] }
pages/shop/[...slug].js | /shop/a/b/c | { slug: ['a', 'b', 'c'] }
情境圖
程式碼範例
// pages/posts/[id].js
//
// Possible paths:
// - xxx/posts/1
// - xxx/posts/2
export async function getStaticPaths() {
// Handle the route paths to render the correspoding comopnents
return {
paths: [
{
params: { id: 1 },
},
{
params: { id: 2 },
},
],
fallback: false,
}
}
export function getStaticProps(id) {
// Handle the external data to be the props passed into the component
return {
props: { postData }
}
}
// Post component
function Post({ postData }) {
// Render Post component
}
Route param 關係鏈
當使用者在瀏覽器上輸入一段網址: https://xxxx/posts/1
, 該路徑中會對應到上方範例得檔案路徑: pages/posts/[id].js
, 其中路徑上的 1
就是對應到[id]
在 [id].js
檔案中有匯出一個function 名為getStaticPaths
, 這個function 將會定義有哪些路徑可以匹配, 讓使用者可以使用該檔案的component.
如果getStaticPaths
function 有設定id: 1
的路徑, 那麼瀏覽器上將會渲染 [id].js
內的component. 反之, 將會依照getStaticPaths
內設定的 fallback
機制決定要如何渲染無法匹配路徑
的畫面
該如何在getStaticPaths
設定動態路徑的機制? 在Node.js 內, 如果URL路徑上有動態的參數, 那麼在伺服器上處理路徑的變數方式是透過 req.params
找到目前URL 上參數的數值. 在這裏也似有類似的方式, 只是我們反過來定義params
有哪些.
所以, 如果要在getStaticPaths
定義有哪些可匹配的路徑可以用這樣方式定義
[
// xxx/1
{
params: { id: 1 }
},
// xxx/2
{
params: { id: 2 }
}
]
最後, 因為getStaticPaths
會回傳給Next.js 的回傳值, 不只是需要路徑, 也需要回傳當找不到路徑時, 應該如何處理的機制: fallback
, 所以基本上的回傳內容會是
{
paths: [ ... ],
fallback: false // or true/'blocking'
}
Fallback 機制
Fallback 機制有三種
fallback: false
fallback: true
fallback: ‘blocking’
fallback: false
在這個機制下, 使用者輸入一個錯誤的路徑: xxx/posts/unknown_path
, 當Next.js 發現可以對應的路徑時, 就會顯示404的頁面
Next.js 有預設的404頁面, 也可以自己建立一個404頁面, 只要pages
資料夾底下建立404.js
檔案: /pages/404.js
即可實作客製化的404頁面
預設404頁面
客製化的404頁面
fallback: true
在這個機制下, 如果Next.js無法從getStaticPaths
馬上找到匹配的路徑, 頁面不會
導向404頁面, 而是會導向fallback頁面,
# fallback 頁面的用途
當fallback: true 時, Next.js 會在build time 的時候, 根據getStaticPaths
回傳的路徑, 產生對應的HTML. 但當User 輸入一個URL無法在getStaticPaths
回傳的路徑找到匹配的路徑, 那麼畫面就會進入到 fallback 頁面(通常顯示載入中
或是表達等待
的頁面), 此時Next.js 認為該頁面是需要動態產生的, 所以不會顯示404頁面, 而是等待 getStaticProps
function 回傳資料後才將fallback 頁面改成產生出來的HTML
大致的程式碼如下
// pages/posts/[id].js
//
// Possible paths:
// - xxx/posts/1
// - xxx/posts/2
import { useRouter } from 'next/router'
export async function getStaticPaths() {
// Handle the route paths to render the correspoding comopnents
return {
...
fallback: true, // <---- 修改上方的範例, 將fallback從false改成true
}
}
export function getStaticProps(id) {
// Handle the external data to be the props passed into the component
return {
props: { postData }
}
}
// Post component
function Post({ postData }) {
const { isFallback } = useRouter()
if(isFallback){
// Fallback page
return <div>Loading...</div>
}
// Render Post component
}
以上面的程式碼為例, 現在在build time 的時候, Next.js 會產生post 1與post 2 的HTML, 當使用者拜訪/posts/1
時, server 可以馬上回傳HTML給使用者.
如果使用者在URL輸入 /posts/3
, 此時因為Server 在編譯出來的檔案內找不到post 3的檔案, 所以畫面就會出現fallback 畫面, 並等待getStaticProps
回傳props資料. getStaticProps
成功回傳資料後, 即會顯示post 3 頁面內容
不過也有些情況不會顯示fallback 畫面
- 當使用者拜訪的URL 未在
getStaticPaths
回傳的路徑內時, 只有首次
拜訪該頁面的時候才會出現fallback 畫面, 該頁面被產生後, 會被儲存在server 內. 所以不需要再顯示fallback畫面 - 當使用者是透過
next/link
,next/rotuer
來拜訪這些頁面, 也不會出現fallback畫面
# 如何導向404頁面
還是有可能會遇到一種情況是, getStaticProps
無法回傳props 資料或是在取得props資料時發生錯誤, 那麼該情況下, 新的HTML頁面無法產生, 就無法顯示新的頁面內容.
此時我們需要用404頁面來輔助我們網站顯示錯誤頁面的訊息.
可能的做法: 我們可以讓 getStaticProps
回傳notFound: true
, 那麼當真的無法顯示畫面時, 可以導向404頁面給使用者而不是顯示程式錯誤的訊息
範例如下
function getStaticProps() {
try {
// Handle the external data to be the props passed into the component
}
catch {
return {
notFound: true
}
}
}
# fallback設計的好處
如果沒有這樣的設計, 當網站內容越來越大時, 我們必須要在 getStaticPaths
加入所有頁面的路徑, 並且在build time時需要編譯/打包所有的頁面, 導致server 需要花費大量的時候來編譯出所有的頁面.
# 注意事項
fallback 等待時所產生的頁面只會產生一次, 所以頁面內的內容不會再更新, 如果需要更新需要參考Incremental Static Regeneration的做法
fallback: blocking
其流程跟fallback: true的流程類似:
- Build time 會根據
getStaticPaths
回傳的路徑產生對應的HTML檔案 - 不會導向404 頁面
- 新產生的HTML只會執行一次, 產生後的HTML會被server 快取, 之後再有相同的路徑直接使用快取內的HTML
- 不會更新已經產生過的HTML 的內容, 需要參考Incremental Static Regeneration的做法
唯一不一樣的地方是, fallback: blocking
不會出現fallbak頁面. 他就跟一般網頁轉址一樣, 在等待新的HTML產生出來的期間, 只會停留在目前的頁面,等到新的頁面產生出來後, 才會轉跳到新的頁面