主题
useFetch
Reactive Fetch API 提供了中止请求、在请求发送前拦截请求、当 URL 变化时自动重新获取请求以及使用预定义选项创建你自己的 useFetch 的功能。
🌐 Reactive Fetch API provides the ability to abort requests, intercept requests before they are fired, automatically refetch requests when the url changes, and create your own useFetch with predefined options.
TIP
在使用 Nuxt 3 时,为了使用 Nuxt 内置的 useFetch(),此函数不会被自动导入。如果你想使用 VueUse 中的函数,请显式导入。
示例
The following URLs can be used to test different features of useFetch
Normal Request:
https://httpbin.org/get Abort Request:
https://httpbin.org/delay/10 Response Error:
http://httpbin.org/status/500 isFinished: false isFetching: false canAbort: false statusCode: null error: null data: null
用法
🌐 Usage
基本用法
🌐 Basic Usage
useFetch 函数可以通过提供一个 URL 来使用。URL 可以是字符串或 ref。data 对象将包含请求的结果,error 对象将包含任何错误,而 isFetching 对象将指示请求是否正在加载。
🌐 The useFetch function can be used by simply providing a url. The url can be either a string or a ref. The data object will contain the result of the request, the error object will contain any errors, and the isFetching object will indicate if the request is loading.
ts
import { useFetch } from '@vueuse/core'
const { isFetching, error, data } = useFetch(url)异步使用
🌐 Asynchronous Usage
useFetch 也可以像普通 fetch 一样被等待。请注意,每当一个组件是异步的,使用它的任何组件都必须将该组件封装在 <Suspense> 标签中。你可以在 官方 Vue 3 文档 中阅读更多关于 suspense API 的内容。
ts
const { isFetching, error, data } = await useFetch(url)URL 更改时重新获取
🌐 Refetching on URL change
在 URL 参数中使用 ref 将允许 useFetch 函数在 URL 更改时自动触发另一个请求。
🌐 Using a ref for the url parameter will allow the useFetch function to automatically trigger another request when the url is changed.
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防止立即触发请求
🌐 Prevent request from firing immediately
将 immediate 选项设置为 false 将阻止请求触发,直到调用 execute 函数为止。
🌐 Setting the immediate option to false will prevent the request from firing until the execute function is called.
ts
const { execute } = useFetch(url, { immediate: false })
execute()中止请求
🌐 Aborting a request
可以通过在 useFetch 函数中使用 abort 函数来中止请求。canAbort 属性表示请求是否可以被中止。
🌐 A request can be aborted by using the abort function from the useFetch function. The canAbort property indicates if the request can be aborted.
ts
const { abort, canAbort } = useFetch(url)
setTimeout(() => {
if (canAbort.value)
abort()
}, 100)请求也可以通过使用 timeout 属性自动中止。当达到指定的超时时间时,它将调用 abort 函数。
🌐 A request can also be aborted automatically by using timeout property. It will call abort function when the given timeout is reached.
ts
const { data } = useFetch(url, { timeout: 100 })拦截请求
🌐 Intercepting a request
beforeFetch 选项可以在请求发送之前拦截请求,并修改请求选项和 URL。
🌐 The beforeFetch option can intercept a request before it is sent and modify the request options and 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 选项可以在响应数据更新之前进行拦截。
🌐 The afterFetch option can intercept the response data before it is updated.
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 选项可以在响应数据和错误更新之前进行拦截。
🌐 The onFetchError option can intercept the response data and error before it is updated when updateDataOnError is set to true.
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' }设置请求方法和返回类型
🌐 Setting the request method and return type
可以通过在 useFetch 末尾添加相应的方法来设置请求方法和返回类型
🌐 The request method and return type can be set by adding the appropriate methods to the end of 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()创建自定义实例
🌐 Creating a Custom Instance
createFetch 函数将返回一个 useFetch 函数,并附带提供给它的任何预先配置的选项。这在整个应用中与 API 交互时非常有用,尤其是当使用相同的基础 URL 或需要授权头时。
🌐 The createFetch function will return a useFetch function with whatever pre-configured options that are provided to it. This is useful for interacting with API's throughout an application that uses the same base URL or needs Authorization headers.
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')如果你想控制 beforeFetch、afterFetch、onFetchError 在预配置实例和新生成实例之间的行为,你可以提供一个 combination 选项来在 overwrite 或 chaining 之间切换。
🌐 If you want to control the behavior of beforeFetch, afterFetch, onFetchError between the pre-configured instance and newly spawned instance. You can provide a combination option to toggle between overwrite or chaining.
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,
}
},
})你可以通过调用 afterFetch 或 onFetchError 中的 execute 方法重新执行请求。以下是一个刷新令牌的简单示例:
🌐 You can re-execute the request by calling the execute method in afterFetch or onFetchError. Here is a simple example of refreshing a 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')事件
🌐 Events
onFetchResponse 和 onFetchError 将分别在获取请求的响应和错误时触发。
🌐 The onFetchResponse and onFetchError will fire on fetch request responses and errors respectively.
ts
const { onFetchResponse, onFetchError } = useFetch(url)
onFetchResponse((response) => {
console.log(response.status)
})
onFetchError((error) => {
console.error(error.message)
})