function useQuery<TQueryFnData, TError, TData, TQueryKey>(options, queryClient?): UseQueryDefinedReturnType<TData, TError>;Defined in: vue-query/src/useQuery.ts:138
This overload is selected when initialData is set, so the resulting data is never undefined.
enabled tracks reactive dependencies automatically as a ref, a plain value, or a reactive getter (() => ...). queryKey reacts through a ref for the array itself, or refs and reactive getters as individual entries — the array itself can't be a bare getter. Other options are read once and are not reactive.
TQueryFnData = unknown
TError = Error
TData = TQueryFnData
TQueryKey extends readonly unknown[] = readonly unknown[]
DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
The DefinedInitialQueryOptions to use — everything you can pass to useQuery, with initialData set.
Use this to use a custom QueryClient. Otherwise, the one provided by VueQueryPlugin will be used.
UseQueryDefinedReturnType<TData, TError>
The current query result, typed so that data is never undefined (status never resolves to pending in this overload's type, since initialData guarantees data upfront).
<script setup lang="ts">
import { useQuery } from '@tanstack/vue-query'
// `data` is `Post[]`, never `undefined`, thanks to `initialData` — even if a refetch fails,
// so the list stays visible alongside the error.
const { data, isError, error } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
initialData: [],
})
</script>
<template>
<span v-if="isError">Error: {{ error.message }}</span>
<ul>
<li v-for="post in data" :key="post.id">{{ post.title }}</li>
</ul>
</template>function useQuery<TQueryFnData, TError, TData, TQueryKey>(options, queryClient?): UseQueryReturnType<TData, TError>;Defined in: vue-query/src/useQuery.ts:279
enabled tracks reactive dependencies automatically as a ref, a plain value, or a reactive getter (() => ...). queryKey reacts through a ref for the array itself, or refs and reactive getters as individual entries — the array itself can't be a bare getter. Other options are read once and are not reactive.
TQueryFnData = unknown
TError = Error
TData = TQueryFnData
TQueryKey extends readonly unknown[] = readonly unknown[]
UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
The UndefinedInitialQueryOptions to use — everything you can pass to useQuery.
Use this to use a custom QueryClient. Otherwise, the one provided by VueQueryPlugin will be used.
UseQueryReturnType<TData, TError>
The current query result. status is pending if there is no cached data to display, error if the last fetch attempt failed, or success if the query has data to display.
A query key built from a reactive ref — the query refetches whenever postId changes:
<script setup lang="ts">
import { ref } from 'vue'
import { useQuery } from '@tanstack/vue-query'
const postId = ref(1)
const { status, data, error } = useQuery({
queryKey: ['post', postId],
queryFn: () => fetchPost(postId.value),
})
</script>
<template>
<span v-if="status === 'pending'">Loading...</span>
<span v-else-if="status === 'error'">Error: {{ error.message }}</span>
<h1 v-else>{{ data.title }}</h1>
</template>select derives whatever data a component needs from the cached value, without changing what's actually stored in the cache — the cache still holds the full Post[], but data here is a number:
<script setup lang="ts">
import { useQuery } from '@tanstack/vue-query'
const { data, isPending, isError, error } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
select: (posts) => posts.length,
})
</script>
<template>
<span v-if="isPending">Loading...</span>
<span v-else-if="isError">Error: {{ error.message }}</span>
<span v-else>{{ data }} posts</span>
</template>A dependent query, only enabled once postId is set — use isLoading, not isPending, so the loading state doesn't show while the query is disabled:
<script setup lang="ts">
import { ref } from 'vue'
import { useQuery } from '@tanstack/vue-query'
const props = defineProps<{ postId: number | undefined }>()
const { data, isLoading, isError, error } = useQuery({
queryKey: ['post', props.postId],
queryFn: () => fetchPost(props.postId!),
enabled: () => props.postId != null,
})
</script>
<template>
<span v-if="props.postId == null">Select a post</span>
<span v-else-if="isLoading">Loading...</span>
<span v-else-if="isError">Error: {{ error.message }}</span>
<h1 v-else>{{ data?.title }}</h1>
</template>Seeding a detail query from an already-cached list, to skip the loading state:
<script setup lang="ts">
import { useQuery, useQueryClient } from '@tanstack/vue-query'
const props = defineProps<{ postId: number }>()
const queryClient = useQueryClient()
const { data, isError, error } = useQuery({
queryKey: ['post', props.postId],
queryFn: () => fetchPost(props.postId),
initialData: () =>
queryClient
.getQueryData<Array<Post>>(['posts'])
?.find((post) => post.id === props.postId),
})
</script>
<template>
<span v-if="isError">Error: {{ error.message }}</span>
<h1 v-else>{{ data?.title }}</h1>
</template>Paginated data, keeping the previous page's data visible while the next page loads:
<script setup lang="ts">
import { ref } from 'vue'
import { keepPreviousData, useQuery } from '@tanstack/vue-query'
const page = ref(0)
const { data, isPlaceholderData, isError, error } = useQuery({
queryKey: ['posts', page],
queryFn: () => fetchPosts(page.value),
placeholderData: keepPreviousData,
})
</script>
<template>
<span v-if="isError">Error: {{ error.message }}</span>
<template v-else>
<ul>
<li v-for="post in data" :key="post.id">{{ post.title }}</li>
</ul>
<button :disabled="isPlaceholderData" @click="page++">Next Page</button>
</template>
</template>function useQuery<TQueryFnData, TError, TData, TQueryKey>(options, queryClient?): UseQueryReturnType<TData, TError>;Defined in: vue-query/src/useQuery.ts:355
Fallback overload for options whose initialData presence isn't statically known — for example, a ref/reactive object built up conditionally, rather than a plain object literal. Prefer one of the other overloads when possible, since they infer whether data can be undefined from initialData directly.
enabled tracks reactive dependencies automatically as a ref, a plain value, or a reactive getter (() => ...). queryKey reacts through a ref for the array itself, or refs and reactive getters as individual entries — the array itself can't be a bare getter.
When options itself is a reactive getter, the whole object is re-evaluated on every change to its dependencies, so any option inside it — not just queryKey and enabled — can change over time.
TQueryFnData = unknown
TError = Error
TData = TQueryFnData
TQueryKey extends readonly unknown[] = readonly unknown[]
MaybeRefOrGetter<UseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>>
A ref, plain value, or reactive getter resolving to the UseQueryOptions to use.
Use this to use a custom QueryClient. Otherwise, the one provided by VueQueryPlugin will be used.
UseQueryReturnType<TData, TError>
The current query result, with data typed as possibly undefined.
Passing a whole-options getter so staleTime reacts to a setting stored elsewhere, not just queryKey:
<script setup lang="ts">
import { useQuery } from '@tanstack/vue-query'
const props = defineProps<{ id: number; staleTime: number }>()
const { data } = useQuery(() => ({
queryKey: ['post', props.id],
queryFn: () => fetchPost(props.id),
staleTime: props.staleTime,
}))
</script>
<template>
<h1 v-if="data">{{ data.title }}</h1>
</template>skipToken disables the query in a type-safe way, without a non-null assertion on props.postId — queryFn is only ever called when it's defined. This requires a whole-options getter: queryFn is a single value, not queryKey/enabled, so it isn't itself reactive — the getter is what re-evaluates it on every change to props.postId. refetch doesn't work while queryFn is skipToken — use enabled: false instead if you need to trigger the query manually:
<script setup lang="ts">
import { skipToken, useQuery } from '@tanstack/vue-query'
const props = defineProps<{ postId: number | undefined }>()
const { data, isLoading, isError, error } = useQuery(() => {
const postId = props.postId
return {
queryKey: ['post', postId],
queryFn: postId != null ? () => fetchPost(postId) : skipToken,
}
})
</script>
<template>
<span v-if="props.postId == null">Select a post</span>
<span v-else-if="isLoading">Loading...</span>
<span v-else-if="isError">Error: {{ error.message }}</span>
<h1 v-else>{{ data?.title }}</h1>
</template>