nuxt3学习之数据获取,useFetch的类封装

1,663 阅读1分钟

最近在学习nuxt3,在数据获取上,官方文档推荐使用useFetch,琢磨了一下,通过以前封装axios的经验,利用class封装了useFetch

useFetch 参数类型

function useFetch(
  url: string | Request | Ref<string | Request> | () => string | Request,
  options?: UseFetchOptions<DataT>
): Promise<AsyncData<DataT>>
type UseFetchOptions = {
  key?: string
  method?: string
  query?: SearchParams
  params?: SearchParams
  body?: RequestInit['body'] | Record<string, any>
  headers?: Record<string, string> | [key: string, value: string][] | Headers
  baseURL?: string
  server?: boolean
  lazy?: boolean
  immediate?: boolean
  default?: () => DataT
  transform?: (input: DataT) => DataT
  pick?: string[]
  watch?: WatchSource[]
}
type AsyncData<DataT, ErrorT> = {
  data: Ref<DataT | null>
  pending: Ref<boolean>
  refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
  execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
  error: Ref<ErrorT | null>
}
interface AsyncDataExecuteOptions {
  dedupe?: boolean
}

完整封装代码

import type { AsyncData, UseFetchOptions } from 'nuxt/dist/app/composables'

type Methods = 'GET' | 'POST' | 'DELETE'

export interface IResultData<T> {
  code: number
  data: T
}

export interface IInterceptor extends
    Pick<UseFetchOptions<any>, 'onRequest' | 'onRequestError' | 'onResponse' | 'onResponseError'> {}
    
export interface IConfig {
  baseURL: any
  interceptor?: IInterceptor
}

export interface IOption<T> {
  url: string
  method?: Methods
  query?: any // query -> params
  body?: any
  options?: UseFetchOptions<T>
}

class Request {
  public baseURL: string
  public interceptor: IInterceptor

  constructor({ baseURL, interceptor }: IConfig) {
    this.baseURL = baseURL
    this.interceptor = interceptor as IInterceptor
  }

  request<T = any>({ url, method, query, body, options }: IOption<T>): Promise<AsyncData<T, Error>> {
    return new Promise((resolve, reject) => {
      const newOptions: UseFetchOptions<T> = {
        baseURL: this.baseURL,
        method,
        query,
        body,
        ...options,
        onRequest: this.interceptor?.onRequest,
        onRequestError: this.interceptor?.onRequestError,
        onResponse: this.interceptor?.onResponse,
        onResponseError: this.interceptor?.onResponseError
      }

      useFetch<T>(url, newOptions as any)
        .then((res) => {
          // res => { data:T, pending, refresh, error ... } => AsyncData
          resolve(res as AsyncData<T, Error>)
        })
        .catch((error) => {
          reject(error)
        })
    })
  }

  get<T = any>({ url, query, options }: IOption<T>) {
    return this.request<T>({ url, method: 'GET', query, options })
  }

  post<T = any>({ url, body, options }: IOption<T>) {
    return this.request<T>({ url, method: 'POST', body, options })
  }

  delete<T = any>({ url, query, options }: IOption<T>) {
    return this.request<T>({ url, method: 'DELETE', query, options })
  }
}

export default Request

使用

import Request from './request'

import { LOGIN_TOKEN } from '@/global/constants'
import { cookieCache } from '@/utils/cache'
import 'element-plus/es/components/message/style/css'

const request = new Request({
  baseURL: import.meta.env.VITE_BASE_URL,
  interceptor: {
    // 请求成功拦截
    onRequest: ({ options }) => {
      const token = cookieCache.getCache(LOGIN_TOKEN)
      if (token) {
        options.headers = (options.headers as { [key: string]: string }) || ({} as { [key: string]: string })
        options.headers.authorization = token
      }
    },
    // 响应成功拦截
    onResponse({ response }) {
      const { code, message } = response._data
    }
  }
})

export { request }

希望能帮助到大家