Back to Nuxt

useFetch

docs/4.api/2.composables/use-fetch.md

4.4.414.7 KB
Original Source

This composable provides a convenient wrapper around useAsyncData and $fetch. It automatically generates a key based on URL and fetch options, provides type hints for request url based on server routes, and infers API response type.

::note useFetch is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates. ::

Usage

vue
<script setup lang="ts">
const { data, status, error, refresh, clear } = await useFetch('/api/modules', {
  pick: ['title'],
})
</script>

::tip{to="/docs/4.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch"} Need a custom useFetch with pre-defined defaults (like baseURL or auth headers)? Use createUseFetch to create a fully typed custom composable. ::

::note data, status, and error are Vue refs, and they should be accessed with .value when used within the <script setup>, while refresh/execute and clear are plain functions. ::

Using the query option, you can add search parameters to your query. This option is extended from unjs/ofetch and is using unjs/ufo to create the URL. Objects are automatically stringified.

ts
const param1 = ref('value1')
const { data, status, error, refresh } = await useFetch('/api/modules', {
  query: { param1, param2: 'value2' },
})

The above example results in https://api.nuxt.com/modules?param1=value1&param2=value2.

You can also use interceptors:

ts
const { data, status, error, refresh, clear } = await useFetch('/api/auth/login', {
  onRequest ({ request, options }) {
    // Set the request headers
    // note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile
    options.headers.set('Authorization', '...')
  },
  onRequestError ({ request, options, error }) {
    // Handle the request errors
  },
  onResponse ({ request, response, options }) {
    // Process the response data
    localStorage.setItem('token', response._data.token)
  },
  onResponseError ({ request, response, options }) {
    // Handle the response errors
  },
})

Reactive Keys and Shared State

You can use a computed ref or a plain ref as the URL, allowing for dynamic data fetching that automatically updates when the URL changes:

vue
<script setup lang="ts">
const route = useRoute()
const id = computed(() => route.params.id)

// When the route changes and id updates, the data will be automatically refetched
const { data: post } = await useFetch(() => `/api/posts/${id.value}`)
</script>

When using useFetch with the same URL and options in multiple components, they will share the same data, error and status refs. This ensures consistency across components.

::tip Keyed state created using useFetch can be retrieved across your Nuxt application using useNuxtData. ::

::warning useFetch is a reserved function name transformed by the compiler, so you should not name your own function useFetch. To create a custom variant with pre-defined options, use createUseFetch instead. ::

::warning If you encounter the data variable destructured from a useFetch returns a string and not a JSON parsed object then make sure your component doesn't include an import statement like import { useFetch } from '@vueuse/core. ::

:video-accordion{title="Watch the video from Alexander Lichter to avoid using useFetch the wrong way" videoId="njsGVmcWviY"}

:read-more{to="/docs/4.x/getting-started/data-fetching"}

Reactive Fetch Options

Fetch options can be provided as reactive, supporting computed, ref and computed getters. When a reactive fetch option is updated it will trigger a refetch using the updated resolved reactive value.

ts
const searchQuery = ref('initial')
const { data } = await useFetch('/api/search', {
  query: { q: searchQuery },
})
// triggers a refetch: /api/search?q=new%20search
searchQuery.value = 'new search'

If needed, you can opt out of this behavior using watch: false:

ts
const searchQuery = ref('initial')
const { data } = await useFetch('/api/search', {
  query: { q: searchQuery },
  watch: false,
})
// does not trigger a refetch
searchQuery.value = 'new search'

Type

ts
export function useFetch<DataT, ErrorT> (
  url: string | Request | Ref<string | Request> | (() => string | Request),
  options?: UseFetchOptions<DataT>,
): Promise<AsyncData<DataT, ErrorT>>

type UseFetchOptions<DataT> = {
  key?: MaybeRefOrGetter<string>
  method?: MaybeRefOrGetter<string>
  query?: MaybeRefOrGetter<SearchParams>
  params?: MaybeRefOrGetter<SearchParams>
  body?: MaybeRefOrGetter<RequestInit['body'] | Record<string, any>>
  headers?: MaybeRefOrGetter<Record<string, string> | [key: string, value: string][] | Headers>
  baseURL?: MaybeRefOrGetter<string>
  cache?: false | 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload'
  server?: boolean
  lazy?: boolean
  immediate?: boolean
  getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined
  deep?: boolean
  dedupe?: 'cancel' | 'defer'
  timeout?: number
  default?: () => DataT
  transform?: (input: DataT) => DataT | Promise<DataT>
  pick?: string[]
  $fetch?: typeof globalThis.$fetch
  watch?: MultiWatchSources | false
}

type AsyncDataRequestContext = {
  /** The reason for this data request */
  cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch'
}

type AsyncData<DataT, ErrorT> = {
  data: Ref<DataT | undefined>
  pending: Ref<boolean>
  refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
  execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
  clear: () => void
  error: Ref<ErrorT | undefined>
  status: Ref<AsyncDataRequestStatus>
}

interface AsyncDataExecuteOptions {
  dedupe?: 'cancel' | 'defer'
  timeout?: number
  signal?: AbortSignal
}

type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'

Parameters

  • URL (string | Request | Ref<string | Request> | () => string | Request): The URL or request to fetch. Can be a string, a Request object, a Vue ref, or a function returning a string/Request. Supports reactivity for dynamic endpoints.

  • options (object): Configuration for the fetch request. Extends unjs/ofetch options and AsyncDataOptions. All options can be a static value, a ref, or a computed value.

OptionTypeDefaultDescription
keyMaybeRefOrGetter<string>auto-genUnique key for de-duplication. If not provided, generated from URL and options.
methodMaybeRefOrGetter<string>'GET'HTTP request method.
queryMaybeRefOrGetter<SearchParams>-Query/search params to append to the URL. Alias: params.
paramsMaybeRefOrGetter<SearchParams>-Alias for query.
bodyMaybeRefOrGetter<RequestInit['body'] | Record<string, any>>-Request body. Objects are automatically stringified.
headersMaybeRefOrGetter<Record<string, string> | [key, value][] | Headers>-Request headers.
baseURLMaybeRefOrGetter<string>-Base URL for the request.
cachefalse | string-Cache control. Boolean disables cache, or use Fetch API values: default, no-store, etc.
serverbooleantrueWhether to fetch on the server.
lazybooleanfalseIf true, resolves after route loads (does not block navigation).
immediatebooleantrueIf false, prevents request from firing immediately.
default() => DataT-Factory for default value of data before async resolves.
timeoutnumber-A number in milliseconds to wait before timing out the request (defaults to undefined, which means no timeout)
transform(input: DataT) => DataT | Promise<DataT>-Function to transform the result after resolving.
getCachedData(key, nuxtApp, ctx) => DataT | undefined-Function to return cached data. See below for default.
pickstring[]-Only pick specified keys from the result.
watchMultiWatchSources | false-Array of reactive sources to watch and auto-refresh. false disables watching.
deepbooleanfalseReturn data in a deep ref object.
dedupe'cancel' | 'defer''cancel'Avoid fetching same key more than once at a time.
$fetchtypeof globalThis.$fetch-Custom $fetch implementation. See Custom useFetch in Nuxt

::note All fetch options can be given a computed or ref value. These will be watched and new requests made automatically with any new values if they are updated. ::

getCachedData default:

ts
const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating
  ? nuxtApp.payload.data[key]
  : nuxtApp.static.data[key]

This only caches data when experimental.payloadExtraction in nuxt.config is enabled.

Return Values

NameTypeDescription
dataRef<DataT | undefined>The result of the asynchronous fetch.
refresh(opts?: AsyncDataExecuteOptions) => Promise<void>Function to manually refresh the data. By default, Nuxt waits until a refresh is finished before it can be executed again.
execute(opts?: AsyncDataExecuteOptions) => Promise<void>Alias for refresh.
errorRef<ErrorT | undefined>Error object if the data fetching failed.
statusRef<'idle' | 'pending' | 'success' | 'error'>Status of the data request. See below for possible values.
pendingRef<boolean>Boolean flag indicating whether the current request is in progress.
clear() => voidResets data to undefined (or the value of options.default() if provided), error to undefined, set status to idle, and cancels any pending requests.

Status values

  • idle: Request has not started (e.g. { immediate: false } or { server: false } on server render)
  • pending: Request is in progress
  • success: Request completed successfully
  • error: Request failed

::note If you have not fetched data on the server (for example, with server: false), then the data will not be fetched until hydration completes. This means even if you await useFetch on client-side, data will remain null within <script setup>. ::

Examples

:link-example{to="/docs/4.x/examples/advanced/use-custom-fetch-composable"}

:link-example{to="/docs/4.x/examples/features/data-fetching"}