需求:將錯誤的文章路徑導向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!&nbsp;&nbsp;</span>Something's gone wrong.. </div> <h2 class="error"> ERROR CODE:&nbsp;&nbsp;<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()去配對...
我也不知道為什麼!求大神解釋了!