起因是因為每次在串API的時候,都要重複的寫 isLoading 狀態,雖然有 useFetch 提供有 pending 可以獲取,但總之就是碰到了,看到大神同事把他封裝起來,就來紀錄一下。
專案使用Nuxt3 + Vue3
API封裝使用ofetch(官方推薦) (以下不會提到)
也紀錄一下泛型(Generics) + function的寫法
function useGenerics<T>(params: T[]): T[] {
return params;
}
T表示Type的縮寫,它可以是任何字。這個function是說傳入的參數是任何東西的數組,回傳也會是跟傳入東西樣的數組。當然你也可以傳入不只一個泛型,比如以下API封裝的函式。
const useMutationApi = <TData, TParams>(
apiFn: (params: TParams) => Promise<TData>
) => {
...
}
(apiFn: (params: TParams) => Promise) 是函數參數。一個接受 apiFn 參數的函數。
接受類型為 TParams 的 params(泛型參數,用於輸入參數),並返回類型 TData(泛型参数,用於返回類型)的 Promise。apiFn 是你想要進行的 API 調用。這邊沒有給返回的Type是因為typescript會自己推斷,要寫也是可以,就會有點多此一舉。
封裝函示寫在 composables 資料夾裡,這樣在組件或頁面上就可以直接使用。
// composables/useMutationApi.ts
export const useMutationApi = <TData = any, TParams = any>(
apiFn: (params: TParams) => Promise<TData>
) => {
const isLoading = ref(false)
const IS_LOADING = computed(() => isLoading.value)
const executeApi = async (params: TParams) => {
isLoading.value = true
try {
const result = await apiFn(params)
return result
} finally {
isLoading.value = false
}
}
return {
executeApi,
IS_LOADING
}
}
在組件中的使用方式:
<button :is-loading="userIsLoading" @click="user">User</button>
import {fetchUserData} from '@/api'
const { executeApi: userMutate, IS_LOADING: userIsLoading } = useMutationApi(fetchUserData)
const user = () => {
userMutate({yourParams})
}
這樣你在打API的時候就會幫你抓到 loading 狀態,不用每次打 API 都要一個 function 寫一次狀態。