Skip to content

useFetch

类别
导出体积
2.28 kB
上次更改
1 hour ago

响应式 Fetch API 提供了中止请求、在请求发送前拦截请求、当 URL 变化时自动重新请求、以及创建带有预定义选项的 useFetch 功能的能力。

通过 Vue School 的这个免费 视频课程学习 useFetch!

TIP

在使用 Nuxt 3 时,此功能将 不会 自动导入,而是使用 Nuxt 内置的 useFetch()。如果您想使用 VueUse 中的函数,请使用显式导入。

示例

以下URL可用于测试useFetch的不同功能
普通请求: https://httpbin.org/get
中止请求: https://httpbin.org/delay/10
响应错误: http://httpbin.org/status/500
isFinished: false
isFetching: false
canAbort: false
statusCode: null
error: null
data: null

用法

基本用法

useFetch 函数可以通过简单提供一个 URL 来使用。URL 可以是一个字符串或一个 refdata 对象将包含请求的结果,error 对象将包含任何错误,而 isFetching 对象将指示请求是否正在加载。

ts
import { 
useFetch
} from '@vueuse/core'
const {
isFetching
,
error
,
data
} =
useFetch
(url)

异步用法

useFetch 也可以像普通的 fetch 一样被 await。请注意,任何异步组件都必须将使用它的组件包裹在 <Suspense> 标签中。您可以在 官方 Vue 3 文档 中了解更多关于 suspense API 的信息。

ts
const { 
isFetching
,
error
,
data
} = await
useFetch
(url)

URL 变化时重新请求

使用 ref 作为 URL 参数将允许 useFetch 函数在 URL 更改时自动触发另一个请求。

ts
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 函数之前发送。

ts
const { 
execute
} =
useFetch
(url, {
immediate
: false })
execute
()

中止请求

可以使用 useFetch 函数中的 abort 函数中止请求。canAbort 属性指示请求是否可以中止。

ts
const { 
abort
,
canAbort
} =
useFetch
(url)
setTimeout
(() => {
if (
canAbort
.
value
)
abort
()
}, 100)

也可以通过使用 timeout 属性自动中止请求。当达到给定的超时时间时,它将调用 abort 函数。

ts
const { 
data
} =
useFetch
(url, {
timeout
: 100 })

拦截请求

beforeFetch 选项可以在请求发送之前拦截请求并修改请求选项和 URL。

ts
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 选项可以在响应数据更新之前拦截响应数据。

ts
const { 
data
} =
useFetch
(url, {
afterFetch
(
ctx
) {
if (
ctx
.
data
.title === 'HxH')
ctx
.
data
.title = 'Hunter x Hunter' // 修改响应数据
return
ctx
}, })

onFetchError 选项可以在将响应数据和错误更新之前拦截它们,前提是 updateDataOnError 设置为 true

ts
const { 
data
} =
useFetch
(url, {
updateDataOnError
: true,
onFetchError
(
ctx
) {
// ctx.data 在 5xx 响应时可能为 null if (
ctx
.
data
=== null)
ctx
.
data
= {
title
: 'Hunter x Hunter' } // 修改响应数据
ctx
.
error
= new
Error
('自定义错误') // 修改错误
return
ctx
}, })
console
.
log
(
data
.
value
) // { title: 'Hunter x Hunter' }

设置请求方法和返回类型

通过在 useFetch 的末尾添加适当的方法可以设置请求方法和返回类型。

ts
// 请求将使用 GET 方法发送,并且数据将解析为 JSON
const { 
data
} =
useFetch
(url).
get
().
json
()
// 请求将使用 POST 方法发送,并且数据将解析为文本 const {
data
} =
useFetch
(url).
post
().
text
()
// 或使用选项设置方法 // 请求将使用 GET 方法发送,并且数据将解析为 blob const {
data
} =
useFetch
(url, {
method
: 'GET' }, {
refetch
: true }).
blob
()

创建自定义实例

createFetch 函数将返回一个带有任何预配置选项的 useFetch 函数。这对于在使用相同基础 URL 或需要授权头的应用程序中与 API 进行交互非常有用。

ts
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')

如果您想在预配置实例和新生成实例之间控制 beforeFetchafterFetchonFetchError 的行为,您可以提供一个 combination 选项以切换 overwritechaining

ts
const 
useMyFetch
=
createFetch
({
baseUrl
: 'https://my-api.com',
combination
: 'overwrite',
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
,
} }, })

您可以通过在 afterFetchonFetchError 中调用 execute 方法来重新执行请求。以下是刷新令牌的简单示例:

ts
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)
onRefreshed
()
} 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
onRefreshed
() {
refreshSubscribers
.
forEach
(
callback
=>
callback
())
refreshSubscribers
.
length
= 0
} function
addRefreshSubscriber
(
callback
: () => void) {
refreshSubscribers
.
push
(
callback
)
} const {
isFetching
,
error
,
data
} =
useMyFetch
('users')
js
let isRefreshing = false
const refreshSubscribers = []
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)
              onRefreshed()
            } 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('refresh-token', {
    immediate: false,
  })
  await execute()
  return data
}
function onRefreshed() {
  refreshSubscribers.forEach((callback) => callback())
  refreshSubscribers.length = 0
}
function addRefreshSubscriber(callback) {
  refreshSubscribers.push(callback)
}
const { isFetching, error, data } = useMyFetch('users')

事件

onFetchResponseonFetchError 将分别在 fetch 请求响应和错误时触发。

ts
const { 
onFetchResponse
,
onFetchError
} =
useFetch
(url)
onFetchResponse
((
response
) => {
console
.
log
(
response
.
status
)
})
onFetchError
((
error
) => {
console
.
error
(
error
.message)
})

类型声明

显示类型声明
ts
export interface 
UseFetchReturn
<
T
> {
/** * 表示 fetch 请求是否已完成 */
isFinished
:
Readonly
<
ShallowRef
<boolean>>
/** * HTTP fetch 响应的 statusCode */
statusCode
:
ShallowRef
<number | null>
/** * fetch 响应的原始数据 */
response
:
ShallowRef
<Response | null>
/** * 可能发生的任何 fetch 错误 */
error
:
ShallowRef
<any>
/** * 成功时的 fetch 响应体,可能是 JSON 或文本 */
data
:
ShallowRef
<
T
| null>
/** * 表示当前是否正在进行 fetch 请求 */
isFetching
:
Readonly
<
ShallowRef
<boolean>>
/** * 表示 fetch 请求是否可以中止 */
canAbort
:
ComputedRef
<boolean>
/** * 表示 fetch 请求是否已中止 */
aborted
:
ShallowRef
<boolean>
/** * 中止 fetch 请求 */
abort
: (
reason
?: any) => void
/** * 手动调用 fetch * (默认不抛出错误) */
execute
: (
throwOnFailed
?: boolean) =>
Promise
<any>
/** * 在 fetch 请求完成后触发 */
onFetchResponse
:
EventHookOn
<Response>
/** * 在 fetch 请求错误后触发 */
onFetchError
:
EventHookOn
/** * 在 fetch 完成后触发 */
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 { /** * 当前请求的计算后的 URL */
url
: string
/** * 当前请求的请求选项 */
options
: RequestInit
/** * 取消当前请求 */
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 函数 */
fetch
?: typeof
window
.
fetch
/** * 当 `useFetch` 被使用时是否自动运行 fetch * * @default true */
immediate
?: boolean
/** * 当以下情况发生时是否自动重新获取: * - 如果 URL 是一个 ref,则 URL 被更改 * - 如果 payload 是一个 ref,则 payload 被更改 * * @default false */
refetch
?:
MaybeRefOrGetter
<boolean>
/** * 请求完成之前的初始数据 * * @default null */
initialData
?: any
/** * 在多少毫秒后中止请求 * `0` 表示使用浏览器默认值 * * @default 0 */
timeout
?: number
/** * 允许在发生 fetch 错误时更新 `data` ref,无论是在提供的回调函数中还是在 `onFetchError` 回调中改变 * * @default false */
updateDataOnError
?: boolean
/** * 在 fetch 请求被分派之前立即运行 */
beforeFetch
?: (
ctx
: BeforeFetchContext,
) => |
Promise
<
Partial
<BeforeFetchContext> | void>
|
Partial
<BeforeFetchContext>
| void /** * 在 fetch 请求返回后立即运行。 * 在任何 2xx 响应之后运行 */
afterFetch
?: (
ctx
:
AfterFetchContext
,
) =>
Promise
<
Partial
<
AfterFetchContext
>> |
Partial
<
AfterFetchContext
>
/** * 在 fetch 请求返回后立即运行。 * 在任何 4xx 和 5xx 响应之后运行 */
onFetchError
?: (
ctx
:
OnFetchErrorContext
,
) =>
Promise
<
Partial
<
OnFetchErrorContext
>> |
Partial
<
OnFetchErrorContext
>
} export interface CreateFetchOptions { /** * 除非 URL 是绝对的,否则将添加到所有 URL 前面的基础 URL */
baseUrl
?:
MaybeRefOrGetter
<string>
/** * 确定 beforeFetch、afterFetch、onFetchError 的继承行为 * @default 'chain' */
combination
?:
Combination
/** * useFetch 函数的默认选项 */
options
?: UseFetchOptions
/** * fetch 请求的选项 */
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
>>

源码

源码演示文档

贡献者

一纸忘忧

更新日志

没有最近的更新日志