VueUse (original) (raw)

useFetch

Category

Export Size

2.28 kB

Last Changed

6 months ago

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.

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(). Use explicit import if you want to use the function from VueUse.

Demo

sourceplayground (beta)

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

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

ts

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

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

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

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

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

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

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

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

// 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

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

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:

TypeScript

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

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)
})

Type Declarations

Show 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

>>

Source

SourceDemoDocs

Contributors

Anthony Fu

wheat

Anthony Fu

Jelf

Ismail Gjevori

IlyaL

qiang

Robin

丶远方

Vida Xie

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

Changelog

44c0b - feat: support for custom abort reason (#4820)

bf354 - fix: use globalThis.fetch when defaultWindow.fetch not exist (#4765)

7432f - feat(types): deprecate MaybeRef and MaybeRefOrGetter in favor of Vue's native (#4636)

3ca0d - fix: partial overwrite when {combination: 'overwrite'} (#4430)

98a83 - feat: add parameters to the afterFetch and onFetchError (#4499)

59f75 - feat(toValue): deprecate toValue from @vueuse/shared in favor of Vue's native

8a89d - fix: handle empty payload (#4366)

0a9ed - feat!: drop Vue 2 support, optimize bundles and clean up (#4349)

3d29c - feat: infer 'json' type for array payloads (#4329)

f5587 - fix: remove unnecessary spread operator in iterable conversion (#3660)

31d4a - fix: mark isFinished, isFetching readonly (#3616)

a086e - fix: stricter types

3456d - fix: immediately modify the status after the request is completed (#3603)

75ca2 - fix: don't set isFetching to false when a request is aborted because of a refetch (#3479)

945ca - feat: introduce updateDataOnError option (#3092)

b7e3d - fix: generated payloadType on execute (#3251)