--- 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. Learn useFetch with this FREE video lesson from Vue School! ::: 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 `` 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('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 { /** * Indicates if the fetch request has finished */ isFinished: Readonly> /** * The statusCode of the HTTP fetch response */ statusCode: ShallowRef /** * The raw response of the fetch response */ response: ShallowRef /** * Any fetch errors that may have occurred */ error: ShallowRef /** * The fetch response body on success, may either be JSON or text */ data: ShallowRef /** * Indicates if the request is currently being fetched. */ isFetching: Readonly> /** * Indicates if the fetch request is able to be aborted */ canAbort: ComputedRef /** * Indicates if the fetch request was aborted */ aborted: ShallowRef /** * Abort the fetch request */ abort: (reason?: any) => void /** * Manually call the fetch * (default not throwing error) */ execute: (throwOnFailed?: boolean) => Promise /** * Fires after the fetch request has finished */ onFetchResponse: EventHookOn /** * Fires after a fetch request error */ onFetchError: EventHookOn /** * Fires after a fetch has completed */ onFetchFinally: EventHookOn get: () => UseFetchReturn & PromiseLike> post: ( payload?: MaybeRefOrGetter, type?: string, ) => UseFetchReturn & PromiseLike> put: ( payload?: MaybeRefOrGetter, type?: string, ) => UseFetchReturn & PromiseLike> delete: ( payload?: MaybeRefOrGetter, type?: string, ) => UseFetchReturn & PromiseLike> patch: ( payload?: MaybeRefOrGetter, type?: string, ) => UseFetchReturn & PromiseLike> head: ( payload?: MaybeRefOrGetter, type?: string, ) => UseFetchReturn & PromiseLike> options: ( payload?: MaybeRefOrGetter, type?: string, ) => UseFetchReturn & PromiseLike> json: () => UseFetchReturn & PromiseLike> text: () => UseFetchReturn & PromiseLike> blob: () => UseFetchReturn & PromiseLike> arrayBuffer: () => UseFetchReturn & PromiseLike> formData: () => UseFetchReturn & PromiseLike> } 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 { response: Response data: T | null context: BeforeFetchContext execute: (throwOnFailed?: boolean) => Promise } export interface OnFetchErrorContext { error: E data: T | null response: Response | null context: BeforeFetchContext execute: (throwOnFailed?: boolean) => Promise } 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 /** * 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 | void> | Partial | void /** * Will run immediately after the fetch request is returned. * Runs after any 2xx response */ afterFetch?: ( ctx: AfterFetchContext, ) => Promise> | Partial /** * Will run immediately after the fetch request is returned. * Runs after any 4xx and 5xx response */ onFetchError?: ( ctx: OnFetchErrorContext, ) => Promise> | Partial } export interface CreateFetchOptions { /** * The base URL that will be prefixed to all urls unless urls are absolute */ baseUrl?: MaybeRefOrGetter /** * 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( url: MaybeRefOrGetter, ): UseFetchReturn & PromiseLike> export declare function useFetch( url: MaybeRefOrGetter, useFetchOptions: UseFetchOptions, ): UseFetchReturn & PromiseLike> export declare function useFetch( url: MaybeRefOrGetter, options: RequestInit, useFetchOptions?: UseFetchOptions, ): UseFetchReturn & PromiseLike> ```