useFetch
响应式 Fetch API 提供了中止请求、在请求发送前拦截请求、当 URL 改变时自动重新请求,以及通过预定义选项创建自己的 useFetch 实例的能力。
通过 Vue School 的免费视频课程学习 useFetch 吧!
useFetch()。如果您想使用 VueUse 中的此函数,请显式导入。用法
基本用法
useFetch 函数 可以通过简单地提供一个 URL 来使用。URL 可以是字符串或 ref。data 对象将包含请求的结果,error 对象将包含任何错误,而 isFetching 对象将指示请求是否正在加载。
import { useFetch } from '@vueuse/core'
const { isFetching, error, data } = useFetch(url)
异步用法
useFetch 也可以像普通的 fetch 一样使用 await。请注意,无论何时组件是异步的,使用它的组件都必须将其包裹在 <Suspense> 标签中。您可以在官方 Vue 3 文档中阅读有关 suspense API 的更多信息。
import { useFetch } from '@vueuse/core'
const { isFetching, error, data } = await useFetch(url)
URL 更改时重新获取
为 URL 参数使用 ref 将允许 useFetch 函数在 URL 更改时自动触发另一个请求。
const url = ref('https://my-api.com/user/1')
const { data } = useFetch(url, { refetch: true })
url.value = 'https://my-api.com/user/2' // 将触发另一个请求
阻止请求立即发送
将 immediate 选项设置为 false 将阻止请求立即发送,直到调用 execute 函数。
const { execute } = useFetch(url, { immediate: false })
execute()
中止请求
可以使用 useFetch 函数的 abort 函数来中止请求。canAbort 属性指示请求是否可以中止。
const { abort, canAbort } = useFetch(url)
setTimeout(() => {
if (canAbort.value)
abort()
}, 100)
请求也可以通过使用 timeout 属性自动中止。当达到给定的超时时间时,它将调用 abort 函数。
const { data } = useFetch(url, { timeout: 100 })
拦截请求
beforeFetch 选项可以在请求发送前拦截请求并修改请求选项和 URL。
const { data } = useFetch(url, {
async beforeFetch({ url, options, cancel }) {
const myToken = await getMyToken()
if (!myToken)
cancel() // 取消请求
options.headers = {
...options.headers,
Authorization: `Bearer ${myToken}`,
}
return {
options,
}
},
})
afterFetch 选项可以在响应数据更新前拦截响应数据。
const { data } = useFetch(url, {
afterFetch(ctx) {
if (ctx.data.title === 'HxH')
ctx.data.title = 'Hunter x Hunter' // 修改响应数据
return ctx
},
})
当 updateDataOnError 设置为 true 时,onFetchError 选项可以在响应数据和错误更新前拦截它们。
const { data } = useFetch(url, {
updateDataOnError: true,
onFetchError(ctx) {
// 当 5xx 响应时,ctx.data 可能为 null
if (ctx.data === null)
ctx.data = { title: 'Hunter x Hunter' } // 修改响应数据
ctx.error = new Error('Custom Error') // 修改错误
return ctx
},
})
console.log(data.value) // { title: 'Hunter x Hunter' }
设置请求方法和返回类型
可以通过在 useFetch 的末尾添加适当的方法来设置请求方法和返回类型。
// 请求将以 GET 方法发送,数据将解析为 JSON
const { data } = useFetch(url).get().json()
// 请求将以 POST 方法发送,数据将解析为 text
const { data } = useFetch(url).post().text()
// 或者使用选项设置方法
// 请求将以 GET 方法发送,数据将解析为 blob
const { data } = useFetch(url, { method: 'GET' }, { refetch: true }).blob()
创建自定义实例
createFetch 函数将返回一个 useFetch 函数,其中包含提供给它的任何预配置选项。这对于与应用程序中共享相同基础 URL 或需要授权头部的 API 进行交互非常有用。
const useMyFetch = createFetch({
baseUrl: 'https://my-api.com',
options: {
async beforeFetch({ options }) {
const myToken = await getMyToken()
options.headers.Authorization = `Bearer ${myToken}`
return { options }
},
},
fetchOptions: {
mode: 'cors',
},
})
const { isFetching, error, data } = useMyFetch('users')
如果您想控制预配置实例和新生成的实例之间的 beforeFetch、afterFetch、onFetchError 的行为。您可以提供一个 combination 选项来在 overwrite 或 chaining 之间切换。
const useMyFetch = createFetch({
baseUrl: 'https://my-api.com',
combination: 'overwrite', // 或者 'chaining'
options: {
// 预配置实例中的 beforeFetch 仅在新生成的实例未传递 beforeFetch 时运行
async beforeFetch({ options }) {
const myToken = await getMyToken()
options.headers.Authorization = `Bearer ${myToken}`
return { options }
},
},
})
// 使用 useMyFetch 的 beforeFetch
const { isFetching, error, data } = useMyFetch('users')
// 使用自定义 beforeFetch
const { isFetching, error, data } = useMyFetch('users', {
async beforeFetch({ url, options, cancel }) {
const myToken = await getMyToken()
if (!myToken)
cancel()
options.headers = {
...options.headers,
Authorization: `Bearer ${myToken}`,
}
return {
options,
}
},
})
您可以通过在 afterFetch 或 onFetchError 中调用 execute 方法来重新执行请求。这是一个简单的刷新令牌的示例:
let isRefreshing = false
const refreshSubscribers: Array<() => void> = []
const useMyFetch = createFetch({
baseUrl: 'https://my-api.com',
options: {
async beforeFetch({ options }) {
const myToken = await getMyToken()
options.headers.Authorization = `Bearer ${myToken}`
return { options }
},
afterFetch({ data, response, context, execute }) {
if (needRefreshToken) {
if (!isRefreshing) {
isRefreshing = true
refreshToken().then((newToken) => {
if (newToken.value) {
isRefreshing = false
setMyToken(newToken.value)
onRrefreshed()
}
else {
refreshSubscribers.length = 0
// 处理刷新令牌错误
}
})
}
return new Promise((resolve) => {
addRefreshSubscriber(() => {
execute().then((response) => {
resolve({ data, response })
})
})
})
}
return { data, response }
},
// 或者使用 onFetchError 并设置 updateDataOnError
updateDataOnError: true,
onFetchError({ error, data, response, context, execute }) {
// 与 afterFetch 相同
return { error, data }
},
},
fetchOptions: {
mode: 'cors',
},
})
async function refreshToken() {
const { data, execute } = useFetch<string>('refresh-token', {
immediate: false,
})
await execute()
return data
}
function onRrefreshed() {
refreshSubscribers.forEach(callback => callback())
refreshSubscribers.length = 0
}
function addRefreshSubscriber(callback: () => void) {
refreshSubscribers.push(callback)
}
const { isFetching, error, data } = useMyFetch('users')
事件
onFetchResponse 和 onFetchError 将分别在 Fetch 请求响应和错误时触发。
const { onFetchResponse, onFetchError } = useFetch(url)
onFetchResponse((response) => {
console.log(response.status)
})
onFetchError((error) => {
console.error(error.message)
})
类型声明
export interface UseFetchReturn<T> {
/**
* Indicates if the fetch request has finished
*/
isFinished: Readonly<ShallowRef<boolean>>
/**
* The statusCode of the HTTP fetch response
*/
statusCode: ShallowRef<number | null>
/**
* The raw response of the fetch response
*/
response: ShallowRef<Response | null>
/**
* Any fetch errors that may have occurred
*/
error: ShallowRef<any>
/**
* The fetch response body on success, may either be JSON or text
*/
data: ShallowRef<T | null>
/**
* Indicates if the request is currently being fetched.
*/
isFetching: Readonly<ShallowRef<boolean>>
/**
* Indicates if the fetch request is able to be aborted
*/
canAbort: ComputedRef<boolean>
/**
* Indicates if the fetch request was aborted
*/
aborted: ShallowRef<boolean>
/**
* Abort the fetch request
*/
abort: (reason?: any) => void
/**
* Manually call the fetch
* (default not throwing error)
*/
execute: (throwOnFailed?: boolean) => Promise<any>
/**
* Fires after the fetch request has finished
*/
onFetchResponse: EventHookOn<Response>
/**
* Fires after a fetch request error
*/
onFetchError: EventHookOn
/**
* Fires after a fetch has completed
*/
onFetchFinally: EventHookOn
get: () => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
post: (
payload?: MaybeRefOrGetter<unknown>,
type?: string,
) => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
put: (
payload?: MaybeRefOrGetter<unknown>,
type?: string,
) => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
delete: (
payload?: MaybeRefOrGetter<unknown>,
type?: string,
) => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
patch: (
payload?: MaybeRefOrGetter<unknown>,
type?: string,
) => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
head: (
payload?: MaybeRefOrGetter<unknown>,
type?: string,
) => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
options: (
payload?: MaybeRefOrGetter<unknown>,
type?: string,
) => UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
json: <JSON = any>() => UseFetchReturn<JSON> &
PromiseLike<UseFetchReturn<JSON>>
text: () => UseFetchReturn<string> & PromiseLike<UseFetchReturn<string>>
blob: () => UseFetchReturn<Blob> & PromiseLike<UseFetchReturn<Blob>>
arrayBuffer: () => UseFetchReturn<ArrayBuffer> &
PromiseLike<UseFetchReturn<ArrayBuffer>>
formData: () => UseFetchReturn<FormData> &
PromiseLike<UseFetchReturn<FormData>>
}
type Combination = "overwrite" | "chain"
export interface BeforeFetchContext {
/**
* The computed url of the current request
*/
url: string
/**
* The request options of the current request
*/
options: RequestInit
/**
* Cancels the current request
*/
cancel: Fn
}
export interface AfterFetchContext<T = any> {
response: Response
data: T | null
context: BeforeFetchContext
execute: (throwOnFailed?: boolean) => Promise<any>
}
export interface OnFetchErrorContext<T = any, E = any> {
error: E
data: T | null
response: Response | null
context: BeforeFetchContext
execute: (throwOnFailed?: boolean) => Promise<any>
}
export interface UseFetchOptions {
/**
* Fetch function
*/
fetch?: typeof window.fetch
/**
* Will automatically run fetch when `useFetch` is used
*
* @default true
*/
immediate?: boolean
/**
* Will automatically refetch when:
* - the URL is changed if the URL is a ref
* - the payload is changed if the payload is a ref
*
* @default false
*/
refetch?: MaybeRefOrGetter<boolean>
/**
* Initial data before the request finished
*
* @default null
*/
initialData?: any
/**
* Timeout for abort request after number of millisecond
* `0` means use browser default
*
* @default 0
*/
timeout?: number
/**
* Allow update the `data` ref when fetch error whenever provided, or mutated in the `onFetchError` callback
*
* @default false
*/
updateDataOnError?: boolean
/**
* Will run immediately before the fetch request is dispatched
*/
beforeFetch?: (
ctx: BeforeFetchContext,
) =>
| Promise<Partial<BeforeFetchContext> | void>
| Partial<BeforeFetchContext>
| void
/**
* Will run immediately after the fetch request is returned.
* Runs after any 2xx response
*/
afterFetch?: (
ctx: AfterFetchContext,
) => Promise<Partial<AfterFetchContext>> | Partial<AfterFetchContext>
/**
* Will run immediately after the fetch request is returned.
* Runs after any 4xx and 5xx response
*/
onFetchError?: (
ctx: OnFetchErrorContext,
) => Promise<Partial<OnFetchErrorContext>> | Partial<OnFetchErrorContext>
}
export interface CreateFetchOptions {
/**
* The base URL that will be prefixed to all urls unless urls are absolute
*/
baseUrl?: MaybeRefOrGetter<string>
/**
* Determine the inherit behavior for beforeFetch, afterFetch, onFetchError
* @default 'chain'
*/
combination?: Combination
/**
* Default Options for the useFetch function
*/
options?: UseFetchOptions
/**
* Options for the fetch request
*/
fetchOptions?: RequestInit
}
export declare function createFetch(
config?: CreateFetchOptions,
): typeof useFetch
export declare function useFetch<T>(
url: MaybeRefOrGetter<string>,
): UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
export declare function useFetch<T>(
url: MaybeRefOrGetter<string>,
useFetchOptions: UseFetchOptions,
): UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>
export declare function useFetch<T>(
url: MaybeRefOrGetter<string>,
options: RequestInit,
useFetchOptions?: UseFetchOptions,
): UseFetchReturn<T> & PromiseLike<UseFetchReturn<T>>