Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
547 lines
14 KiB
Markdown
547 lines
14 KiB
Markdown
---
|
|
category: Network
|
|
---
|
|
|
|
# useFetch
|
|
|
|
Reactive [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/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.
|
|
|
|
<CourseLink href="https://vueschool.io/lessons/vueuse-utilities-usefetch-and-reactify?friend=vueuse">Learn useFetch with this FREE video lesson from Vue School!</CourseLink>
|
|
|
|
::: tip
|
|
When using with Nuxt 3, this function will **NOT** be auto imported in favor of Nuxt's built-in [`useFetch()`](https://v3.nuxtjs.org/api/composables/use-fetch). Use explicit import if you want to use the function from VueUse.
|
|
:::
|
|
|
|
## Usage
|
|
|
|
### Basic Usage
|
|
|
|
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` can also be awaited just like a normal fetch. Note that whenever a component is asynchronous, whatever component that uses
|
|
it must wrap the component in a `<Suspense>` tag. You can read more about the suspense api in the [Official Vue 3 Docs](https://vuejs.org/guide/built-ins/suspense.html)
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
const { isFetching, error, data } = await useFetch(url)
|
|
```
|
|
|
|
### Refetching on URL change
|
|
|
|
Using a `ref` for the url parameter will allow the `useFetch` function to automatically trigger another request when the url is changed.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
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
|
|
|
|
Setting the `immediate` option to false will prevent the request from firing until the `execute` function is called.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
const { execute } = useFetch(url, { immediate: false })
|
|
|
|
execute()
|
|
```
|
|
|
|
### Aborting a request
|
|
|
|
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
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
const { abort, canAbort } = useFetch(url)
|
|
|
|
setTimeout(() => {
|
|
if (canAbort.value)
|
|
abort()
|
|
}, 100)
|
|
```
|
|
|
|
A request can also be aborted automatically by using `timeout` property. It will call `abort` function when the given timeout is reached.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
const { data } = useFetch(url, { timeout: 100 })
|
|
```
|
|
|
|
### Intercepting a request
|
|
|
|
The `beforeFetch` option can intercept a request before it is sent and modify the request options and url.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
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,
|
|
}
|
|
},
|
|
})
|
|
```
|
|
|
|
The `afterFetch` option can intercept the response data before it is updated.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
const { data } = useFetch(url, {
|
|
afterFetch(ctx) {
|
|
if (ctx.data.title === 'HxH')
|
|
ctx.data.title = 'Hunter x Hunter' // Modifies the response data
|
|
|
|
return ctx
|
|
},
|
|
})
|
|
```
|
|
|
|
The `onFetchError` option can intercept the response data and error before it is updated when `updateDataOnError` is set to `true`.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
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
|
|
|
|
The request method and return type can be set by adding the appropriate methods to the end of `useFetch`
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
// 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
|
|
|
|
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
|
|
import { createFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
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')
|
|
```
|
|
|
|
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
|
|
import { createFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
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,
|
|
}
|
|
},
|
|
})
|
|
```
|
|
|
|
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
|
|
import { createFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
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')
|
|
```
|
|
|
|
### Events
|
|
|
|
The `onFetchResponse` and `onFetchError` will fire on fetch request responses and errors respectively.
|
|
|
|
```ts
|
|
import { useFetch } from '@vueuse/core'
|
|
// ---cut---
|
|
const { onFetchResponse, onFetchError } = useFetch(url)
|
|
|
|
onFetchResponse((response) => {
|
|
console.log(response.status)
|
|
})
|
|
|
|
onFetchError((error) => {
|
|
console.error(error.message)
|
|
})
|
|
```
|
|
|
|
## Type Declarations
|
|
|
|
```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>>
|
|
```
|