Nuxt3 導入 ofetch 作為與遠端伺服器溝通的內建函式庫。這回想將 api 統一放置在一個資料夾,然後讓 Pinia, Nuxt 的 server 端或是 Vue 內都可直接引入呼叫,就如同過往的 axios 一樣。這邊筆記下實現步驟。
內容
utils/index.ts
新增一個 createHttpClient 方法。傳入的參數是 ofetch 的原始 instance,然後回傳你所客製化的 ofetch Instance,包含 onRequest, onResponse, onRequestError, onResponseError … 等
api/demo.ts
定義你的 demoAPI 內容有哪些函式可供呼叫。傳入的參數是你所客製化的 ofetch Instance,最後回傳建立這一系列函式的方法
plugins/api.ts
定義一個 NuxtPlugin,從 useRuntimeConfig() 獲取在 nuxt.config.ts 定義的 baseAPI…等參數內容。
接著引入 api/demo.ts 的內容,將函式建立起來,並使用 nuxtApp.provide 的方法,將內容注入到 Nuxt 和 Vue 的生命週期內
注意事項
1. 由於是直接使用原生的 ofetch (就如同過往的 axios),且 Vue 的程式碼會在 server 和 client 端各跑一次
2. 由於 await 會中斷 Nuxt 的前後上下文導致不一致,因此你的寫法上若要打多個 API,那就得用 Promise.all() 然後用 .then 的方法才能確保上下文的一致性,就無法使用 await 了。如果你不小心違反了,那就會看見以下的錯誤:
[unhandledRejection] [nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function.
官方文件中關於相關內容的說明: On top of that, you must use them synchronously – that is, you cannot use await
before calling a composable……
使用 await
那就摒棄掉 useAsyncData, useFetch 等 hook,直接調用 ofetch Instance,也就是下方的示範方法。若你真的要避免在 server, client 兩端都跑一次,那就將其放入 onMounted 內吧。
程式碼
型別
由於 nuxt 專案在每一次啟用開發 server 時,都會重新生成對應的型別檔於 .type 中。所以你僅需要在根目錄下的 types 資料夾內新增對應的內容,重新開啟一次專案就會抓到了。nuxtApp.provide 所標的 key,都會上 $ 字號
參考資料
1. Multiple “useFetch”-calls lead to Error Nuxt3
2. Vue and Nuxt Composables
3. Nuxt3: useFetch使用过程常见一种报错