跳到主要内容

useFetch

分类
导出大小
2.28 kB
上次更改
4 个月前

响应式的 Fetch API 提供了中止请求、在请求发出前拦截请求、当 url 改变时自动重新获取请求,以及使用预定义选项创建自己的 useFetch 的能力。

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

提示

当与 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

用法

基本用法

只需提供一个 url,即可使用 useFetch 函数。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 更改时重新获取

对 url 参数使用 ref 将允许 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' // Will trigger another request

阻止请求立即触发

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' // Modifies the response data
return
ctx
}, })

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

ts
const { 
data
} =
useFetch
(url, {
updateDataOnError
: true,
onFetchError
(
ctx
) {
// ctx.data can be null when 5xx response if (
ctx
.
data
=== null)
ctx
.
data
= {
title
: 'Hunter x Hunter' } // Modifies the response data
ctx
.
error
= new
Error
('Custom Error') // Modifies the error
return
ctx
}, })
console
.
log
(
data
.
value
) // { title: 'Hunter x Hunter' }

设置请求方法和返回类型

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

ts
// Request will be sent with GET method and data will be parsed as JSON
const { 
data
} =
useFetch
(url).
get
().
json
()
// Request will be sent with POST method and data will be parsed as text const {
data
} =
useFetch
(url).
post
().
text
()
// Or set the method using the options // Request will be sent with GET method and data will be parsed as 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 in pre-configured instance will only run when the newly spawned instance do not pass beforeFetch async
beforeFetch
({
options
}) {
const
myToken
= await getMyToken()
options
.
headers
.Authorization = `Bearer ${
myToken
}`
return {
options
}
}, }, }) // use useMyFetch beforeFetch const {
isFetching
,
error
,
data
} =
useMyFetch
('users')
// use custom 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 方法来重新执行请求。这是一个刷新 token 的简单示例。

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
// handle refresh token error } }) } return new
Promise
((
resolve
) => {
addRefreshSubscriber
(() => {
execute
().
then
((
response
) => {
resolve
({
data
,
response
})
}) }) }) } return {
data
,
response
}
}, // or use onFetchError with updateDataOnError
updateDataOnError
: true,
onFetchError
({
error
,
data
,
response
,
context
,
execute
}) {
// same as 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
              // handle refresh token error
            }
          })
        }
        return new Promise((resolve) => {
          addRefreshSubscriber(() => {
            execute().then((response) => {
              resolve({ data, response })
            })
          })
        })
      }
      return { data, response }
    },
    // or use onFetchError with updateDataOnError
    updateDataOnError: true,
    onFetchError({ error, data, response, context, execute }) {
      // same as 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
> {
/** * 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
>>

来源

源代码演示文档

贡献者

Anthony Fu
wheat
Anthony Fu
Jelf
Ismail Gjevori
IlyaL
qiang
Robin
丶远方
Robin
青椒肉丝
KaKa
Toby Zerner
Jay214
webfansplz
Vic
abeer0
SerKo
IlyaL
Yu Lia
Zero
James Garbutt
Gergely Dremák
mrchar
Pouya Mohammadkhani
BaboonKing
LJFloor
mymx2
Arthur Machado
Martijn Weghorst
KaKa
RAX7
Przemek Brzosko
abitwhy
sun0day
Young
sun0day
Curt Grimes
Yvan Zhu
ice
Antonio Román
Glandos
unknown_
btea
Shinigami
KaKa
Arda Soytürk

更新日志

v13.4.0
44c0b - feat: 支持自定义中止原因 (#4820)
v13.3.0
bf354 - fix: 当 defaultWindow.fetch 不存在时使用 globalThis.fetch (#4765)
v12.8.0
7432f - feat(types): 废弃 MaybeRefMaybeRefOrGetter,转而使用 Vue 的原生类型 (#4636)
v12.7.0
3ca0d - fix: 当 {combination: 'overwrite'} 时部分覆盖 (#4430)
v12.5.0
98a83 - feat: 为 afterFetchonFetchError 添加参数 (#4499)
v12.3.0
59f75 - feat(toValue): 废弃 @vueuse/shared 中的 toValue,转而使用 Vue 的原生函数
v12.1.0
8a89d - fix: 处理空有效载荷 (#4366)
0a9ed - feat!: 放弃对 Vue 2 的支持,优化打包并清理 (#4349)
v11.3.0
3d29c - feat: 为数组有效载荷推断 'json' 类型 (#4329)
3de68 - fix: 确保单个斜杠 (#4296)
v10.8.0
f5587 - fix: 删除可迭代转换中不必要的扩展运算符 (#3660)
31d4a - fix: 标记 isFinished, isFetching 为只读 (#3616)
a086e - fix: 更严格的类型
v10.7.0
fccf2 - feat: 升级依赖 (#3614)
8cbfd - fix: 读取时克隆 'Response' (#3607) (#3608)
3456d - fix: 请求完成后立即修改状态 (#3603)
v10.6.0
75ca2 - fix: 当请求因重新获取而中止时,不将 isFetching 设置为 false (#3479)
v10.4.0
945ca - feat: 引入 updateDataOnError 选项 (#3092)
v10.3.0
b7e3d - fix: 在执行时生成 payloadType (#3251)
v10.1.1
d051f - fix: combineCallbacks 不合并选项 (#3015)

根据 MIT 许可证发布。