Next.js-fallback

稍微複雜一些的機制。

簡述

再解釋之前先說一下什麼時候會用到 Fallback?舉例來說,假設我們有一個這樣的網頁:

demo

首頁是一個食譜列表,接著點進去以後可以看到詳細內容,非常的簡單,而這些資料都是串接 CMS 來產生出的靜態資料(SSG)。

那麼現在思考一個問題:

假設我在 CMS 上加了一個新食譜,那我該怎麼同步到網頁上?

這邊會碰到的問題是「詳細頁面」的內容是透過網址上的 slug 來抓取的,所以會需要:

  1. 產生新的頁面(recipes/peanu-butter-cookie.html
  2. 把對應的資料抓取下來

所以這部分的 code 會大概長這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 產生路徑
export async function getStaticPaths() {
const response = await client.getEntries({
content_type: 'recipe'
})
const paths = response.items.map((recipes) => ({
params: {
slug: recipes.fields.slug
}
}))
return {
paths,
fallback: false
}
}

// 根據路徑抓資料,最後再注入 props
export async function getStaticProps({ params }) {
const response = await client.getEntries({
content_type: 'recipe',
'fields.slug': params.slug
})

return {
props: {
recipe: response.items[0]
},
revalidate: 1
}
}

這邊雖然有利用「Incremental Static Regeneration」來做自動更新內容,但之前有說過他只能幫你更新現有的頁面,沒辦法幫你產生新的 page

所以假設我現在新增了一個叫「abc」的食譜,接著造訪的話只會得到 404 的結果,因為這是一個全新的 page(recipes/abc.html),而 Incremental Static Regeneration 不會幫我產生新的 page。

所以要更新的話就是把整個專案重新 build 以後在重新 deploy 一次。因為是重新產生所有資料,因此內容就會更新。

這樣確實是一種方式。但有沒有更好的作法?像是自動幫我抓取新資料,接著產生對應的頁面?

有,就是本篇的標題 fallback,他就是用來做這件事的。

使用 Fallback

眼尖的話應該能注意到剛剛的範例中其實就有出現 fallback,不過值是 false

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 產生路徑
export async function getStaticPaths() {
const response = await client.getEntries({
content_type: 'recipe'
})
const paths = response.items.map((recipes) => ({
params: {
slug: recipes.fields.slug
}
}))
return {
paths,
fallback: false // 在這裡
}
}

設為 false 的行為就是跳轉到 404 頁面,意思是當我們造訪不存在的頁面(例如:recipe/abc)時,因為找不到對應頁面所以就直接導向 404 頁面。

重點來了,現在我們希望他能「自動抓取新資料 & 產生頁面」的功能,因此要把他設為 true

設為 true 的話當我們在造訪 recipe/abc 時,他會做下面幾件事:

  1. 進入 Fallback Page(通常會做一個 Loading 效果)
  2. 重新執行 getStaticProps,抓取 abc 的食譜資料
  3. 把回傳結果傳入 props,把 recipes/abc 的頁面渲染出來給使用者
  4. 自動在 Server 產生新的 recipes/abc.html,下次就不需要在跑這個流程

附註:如果在第三步抓資料這一段出問題的話,可以做重新導向的動作。

fallback

所以我們只要這樣子改寫就好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
export async function getStaticPaths() {
// ...略

return {
paths,
fallback: true // 打開 fallback 功能
}
}

export async function getStaticProps({ params }) {
const response = await getData()

// 如果抓資料出問題的話,直接導向首頁
if (!response.items.length) {
return {
redirect: {
destination: '/',
permanent: false
}
}
}

return {
props: {
recipe: response.items[0]
},
revalidate: 1
}
}

export default function RecipeDetails({ recipe }) {
// 進入 fallback 頁面
if (!recipe) {
return <Skeleton />
}
const { title, cookingTime, featureImage, ingredients, method } = recipe.fields

return <div>{/*...*/}</div>
}

這樣子就完成啦,我覺得還蠻划算的,只需要簡單加個幾行就能實現。

Contentful 懶人包 Next.js-Incremental Static Regeneration
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×