需求:將錯誤的文章路徑導向error page
本站的文章結構設計為/articles/_articleId
當輸入不存在的_articleId時,希望頁面能自動導向error page
Nuxt在處理error page時,主要有兩種方式,一是在pages folder內新增_.vue檔
不屬於page路徑結構的路徑都會被導向_.vue頁面
然而這沒法處理不存在的_articleId
第二種是在layouts folder新增error.vue,說明請看官網文件
注意一點就是,雖然放在layouts folder內,但error.vue本質上是個page component!
hamsterism的error page程式碼如下:
<template>
<app-wrapper>
<div class="flex flex-col justify-center h-screen-70">
<div class="h1 mb-8">
<span class="oops">Oops! </span>Something's gone wrong..
</div>
<h2 class="error">
ERROR CODE: <span class="error-code">{{
error.statusCode
}}</span>
</h2>
</div>
</app-wrapper>
</template>
<script>
export default {
layout: 'error',
props: {
error: {
type: Object,
default: () => {},
},
},
}
</script>
<style lang="postcss">
.h-screen-70 {
height: 70vh;
}
.h1 {
font-size: 3rem;
overflow-wrap: break-word;
.oops {
font-size: 4rem;
color: var(--btn-color-primary-dark);
}
}
.error {
font-size: 2rem;
&-code {
font-size: 4rem;
}
}
</style>
error.vue內的props error
必帶,Nuxt context的error function會自動將error object丟進這個property
所以我們的目標就變成:想辦法讓Nuxt吐出對應的error({ statusCode: "XXX", message: "OOXXOX" })
Get Article Data from Firebase
由於我直接使用nuxt/firebase module,在向firebase發請求時,我壓根沒用到axios...
先看載入文章的action code吧!
async loadCurrentArticle({ commit }, articleId) {
// console.log('===loadCurrentArticle===')
let article = {}
let articleRef = await this.$fire.database.ref('articles/' + articleId)
await articleRef.once('value', async (snapshot) => {
article = snapshot.val()
await commit('setCurrentArticle', article)
})
return new Promise((resolve, reject) => {
if (!article) {
reject()
}
resolve()
})
},
上述寫法中,由於不管articleId存不存在,我都不會收到firebase吐給我error,它只會吐給我null的article
API請求沒發生錯誤要怎吐錯誤...卡了我一下午
因為大家都用axios處理啊 =口=
解法如上面的code,在action最後return一個Promise物件
在Promise內,透過判定article是否存在,來執行reject() or resolve()
asyncData hook
搞定store action,接著就是如何在asyncData()內catch到reject()了!
上code說明
async asyncData({ store, params, error }) {
let article
await store
.dispatch('articles/loadCurrentArticle', params.articleId)
.then(() => {
article = {
...store.getters['articles/getCurrentArticle'],
}
})
.catch(() => {
error({ statusCode: 404, message: 'Article not found' })
})
return {
id: article.id,
title: article.title,
publicationDate: article.publicationDate,
category: article.category,
tags: article.tags,
description: article.description,
content: article.content,
updatedDate: article.updatedDate ? article.updatedDate : '',
}
},
把route的articleId parameter當作payload,store.dispatch載入當前文章內容的action
由於這個action return Promise,所以你可以.then()和.catch()
在.then()中使用store.getters取得當前文章內容
在.catch()中,呼叫Nuxt context error function,輸入statusCode和message
就這樣,之後每次在render文章頁面前,只要Nuxt接收到error訊息,都會自動跳轉至error.vue的畫面
而且錯誤的路徑還會保留在瀏覽器上唷! (若用redirect方法就無法保留錯誤路徑)
完成!👏👏👏
至於為何.then()內不直接取完值後return下面那一串data呢?感覺很合理啊!
因為會讀不到,return的data object無法正確吐給data()去配對...
我也不知道為什麼!求大神解釋了!