--- 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>; ```