0
# Data Queries
1
2
Core composables for fetching and caching data with reactive state management, automatic background refetching, cache invalidation, and optimistic updates.
3
4
## Capabilities
5
6
### useQuery
7
8
Main composable for data fetching with intelligent caching and background synchronization.
9
10
```typescript { .api }
11
/**
12
* Main composable for data fetching with intelligent caching
13
* @param options - Query configuration options with Vue reactivity support
14
* @param queryClient - Optional query client instance
15
* @returns Reactive query state and utilities
16
*/
17
function useQuery<TQueryFnData, TError, TData, TQueryKey>(
18
options: UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
19
queryClient?: QueryClient
20
): UseQueryReturnType<TData, TError>;
21
22
// Overload for queries with defined initial data
23
function useQuery<TQueryFnData, TError, TData, TQueryKey>(
24
options: DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>,
25
queryClient?: QueryClient
26
): UseQueryDefinedReturnType<TData, TError>;
27
28
interface UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
29
queryKey: MaybeRefOrGetter<TQueryKey>;
30
queryFn?: MaybeRefOrGetter<QueryFunction<TQueryFnData, TQueryKey>>;
31
enabled?: MaybeRefOrGetter<boolean>;
32
staleTime?: MaybeRefOrGetter<number>;
33
gcTime?: MaybeRefOrGetter<number>;
34
refetchInterval?: MaybeRefOrGetter<number | false>;
35
refetchIntervalInBackground?: MaybeRefOrGetter<boolean>;
36
refetchOnMount?: MaybeRefOrGetter<boolean | "always">;
37
refetchOnWindowFocus?: MaybeRefOrGetter<boolean | "always">;
38
refetchOnReconnect?: MaybeRefOrGetter<boolean | "always">;
39
retry?: MaybeRefOrGetter<boolean | number | ((failureCount: number, error: TError) => boolean)>;
40
retryDelay?: MaybeRefOrGetter<number | ((retryAttempt: number, error: TError) => number)>;
41
select?: MaybeRefOrGetter<(data: TQueryFnData) => TData>;
42
placeholderData?: MaybeRefOrGetter<TData | PlaceholderDataFunction<TData>>;
43
initialData?: MaybeRefOrGetter<TData | InitialDataFunction<TData>>;
44
initialDataUpdatedAt?: MaybeRefOrGetter<number | (() => number | undefined)>;
45
throwOnError?: MaybeRefOrGetter<boolean | ((error: TError) => boolean)>;
46
meta?: MaybeRefOrGetter<QueryMeta>;
47
notifyOnChangeProps?: MaybeRefOrGetter<Array<keyof UseQueryReturnType<TData, TError>>>;
48
shallow?: boolean;
49
}
50
51
interface UseQueryReturnType<TData, TError> {
52
data: Ref<TData | undefined>;
53
dataUpdatedAt: Ref<number>;
54
error: Ref<TError | null>;
55
errorUpdatedAt: Ref<number>;
56
failureCount: Ref<number>;
57
failureReason: Ref<TError | null>;
58
fetchStatus: Ref<FetchStatus>;
59
isError: Ref<boolean>;
60
isFetched: Ref<boolean>;
61
isFetchedAfterMount: Ref<boolean>;
62
isFetching: Ref<boolean>;
63
isInitialLoading: Ref<boolean>;
64
isLoading: Ref<boolean>;
65
isLoadingError: Ref<boolean>;
66
isPaused: Ref<boolean>;
67
isPending: Ref<boolean>;
68
isPlaceholderData: Ref<boolean>;
69
isRefetchError: Ref<boolean>;
70
isRefetching: Ref<boolean>;
71
isStale: Ref<boolean>;
72
isSuccess: Ref<boolean>;
73
refetch: (options?: RefetchOptions) => Promise<QueryObserverResult<TData, TError>>;
74
status: Ref<QueryStatus>;
75
suspense: () => Promise<UseQueryReturnType<TData, TError>>;
76
}
77
```
78
79
**Usage Examples:**
80
81
```typescript
82
import { useQuery, keepPreviousData } from '@tanstack/vue-query';
83
84
// Basic query
85
const { data, isLoading, error } = useQuery({
86
queryKey: ['todos'],
87
queryFn: () => fetch('/api/todos').then(res => res.json())
88
});
89
90
// Query with reactive parameters
91
const userId = ref(1);
92
const { data: user } = useQuery({
93
queryKey: () => ['user', userId.value],
94
queryFn: ({ queryKey }) => fetch(`/api/users/${queryKey[1]}`).then(res => res.json()),
95
enabled: () => !!userId.value
96
});
97
98
// Query with data transformation
99
const { data: processedData } = useQuery({
100
queryKey: ['dashboard'],
101
queryFn: () => fetch('/api/dashboard').then(res => res.json()),
102
select: (data) => ({
103
summary: data.metrics.reduce((acc, m) => acc + m.value, 0),
104
items: data.items.filter(item => item.active)
105
})
106
});
107
108
// Query with placeholder data
109
const { data } = useQuery({
110
queryKey: ['posts', page],
111
queryFn: ({ queryKey }) => fetch(`/api/posts?page=${queryKey[1]}`).then(res => res.json()),
112
placeholderData: keepPreviousData
113
});
114
```
115
116
### useInfiniteQuery
117
118
Composable for paginated data fetching with automatic page management and infinite scrolling support.
119
120
```typescript { .api }
121
/**
122
* Composable for paginated data fetching with infinite scrolling
123
* @param options - Infinite query configuration options
124
* @param queryClient - Optional query client instance
125
* @returns Reactive infinite query state with page management
126
*/
127
function useInfiniteQuery<TQueryFnData, TError, TData, TQueryKey, TPageParam>(
128
options: UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>,
129
queryClient?: QueryClient
130
): UseInfiniteQueryReturnType<TData, TError>;
131
132
interface UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
133
extends Omit<UseQueryOptions<TQueryFnData, TError, TData, TQueryKey>, 'queryFn'> {
134
queryFn: MaybeRefOrGetter<
135
(context: QueryFunctionContext<TQueryKey, TPageParam>) => TQueryFnData | Promise<TQueryFnData>
136
>;
137
initialPageParam: MaybeRefOrGetter<TPageParam>;
138
getNextPageParam: MaybeRefOrGetter<
139
(lastPage: TQueryFnData, allPages: TQueryFnData[], lastPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined | null
140
>;
141
getPreviousPageParam?: MaybeRefOrGetter<
142
(firstPage: TQueryFnData, allPages: TQueryFnData[], firstPageParam: TPageParam, allPageParams: TPageParam[]) => TPageParam | undefined | null
143
>;
144
maxPages?: MaybeRefOrGetter<number>;
145
}
146
147
interface UseInfiniteQueryReturnType<TData, TError> extends UseQueryReturnType<TData, TError> {
148
data: Ref<InfiniteData<TData> | undefined>;
149
fetchNextPage: (options?: FetchNextPageOptions) => Promise<InfiniteQueryObserverResult<TData, TError>>;
150
fetchPreviousPage: (options?: FetchPreviousPageOptions) => Promise<InfiniteQueryObserverResult<TData, TError>>;
151
hasNextPage: Ref<boolean>;
152
hasPreviousPage: Ref<boolean>;
153
isFetchingNextPage: Ref<boolean>;
154
isFetchingPreviousPage: Ref<boolean>;
155
}
156
157
interface InfiniteData<TData, TPageParam = unknown> {
158
pages: TData[];
159
pageParams: TPageParam[];
160
}
161
```
162
163
**Usage Examples:**
164
165
```typescript
166
import { useInfiniteQuery } from '@tanstack/vue-query';
167
168
// Basic infinite query
169
const {
170
data,
171
fetchNextPage,
172
hasNextPage,
173
isFetchingNextPage
174
} = useInfiniteQuery({
175
queryKey: ['posts'],
176
queryFn: ({ pageParam = 1 }) =>
177
fetch(`/api/posts?page=${pageParam}`).then(res => res.json()),
178
initialPageParam: 1,
179
getNextPageParam: (lastPage, allPages) =>
180
lastPage.hasNextPage ? allPages.length + 1 : undefined
181
});
182
183
// Infinite query with search
184
const searchTerm = ref('');
185
const {
186
data: searchResults,
187
fetchNextPage: loadMore,
188
hasNextPage,
189
isFetchingNextPage: isLoadingMore
190
} = useInfiniteQuery({
191
queryKey: () => ['search', searchTerm.value],
192
queryFn: ({ queryKey, pageParam = 0 }) =>
193
fetch(`/api/search?q=${queryKey[1]}&offset=${pageParam}`)
194
.then(res => res.json()),
195
initialPageParam: 0,
196
getNextPageParam: (lastPage, allPages, lastPageParam) =>
197
lastPage.results.length === 20 ? lastPageParam + 20 : undefined,
198
enabled: () => searchTerm.value.length > 0
199
});
200
201
// Access flattened data
202
const allPosts = computed(() =>
203
data.value?.pages.flatMap(page => page.posts) ?? []
204
);
205
```
206
207
### useQueries
208
209
Composable for running multiple queries in parallel with individual state management.
210
211
```typescript { .api }
212
/**
213
* Run multiple queries in parallel with individual state management
214
* @param options - Configuration with array of query options and optional combine function
215
* @param queryClient - Optional query client instance
216
* @returns Readonly ref containing array of query results
217
*/
218
function useQueries<T extends Array<any>, TCombinedResult = UseQueriesResults<T>>(
219
options: {
220
queries: MaybeRefOrGetter<UseQueriesOptions<T>>;
221
combine?: (results: UseQueriesResults<T>) => TCombinedResult;
222
shallow?: boolean;
223
},
224
queryClient?: QueryClient
225
): Readonly<Ref<TCombinedResult>>;
226
227
type UseQueriesOptions<T extends Array<any>> = readonly [...{
228
[K in keyof T]: UseQueryOptions<any, any, any, any>
229
}];
230
231
type UseQueriesResults<T extends Array<any>> = {
232
[K in keyof T]: UseQueryReturnType<any, any>
233
};
234
```
235
236
**Usage Examples:**
237
238
```typescript
239
import { useQueries } from '@tanstack/vue-query';
240
241
// Multiple static queries
242
const queries = useQueries({
243
queries: [
244
{
245
queryKey: ['user'],
246
queryFn: () => fetch('/api/user').then(res => res.json())
247
},
248
{
249
queryKey: ['posts'],
250
queryFn: () => fetch('/api/posts').then(res => res.json())
251
},
252
{
253
queryKey: ['notifications'],
254
queryFn: () => fetch('/api/notifications').then(res => res.json())
255
}
256
]
257
});
258
259
// Access individual query results
260
const userQuery = computed(() => queries.value[0]);
261
const postsQuery = computed(() => queries.value[1]);
262
const notificationsQuery = computed(() => queries.value[2]);
263
264
// Dynamic queries based on reactive data
265
const userIds = ref([1, 2, 3]);
266
const userQueries = useQueries({
267
queries: () => userIds.value.map(id => ({
268
queryKey: ['user', id],
269
queryFn: () => fetch(`/api/users/${id}`).then(res => res.json())
270
}))
271
});
272
273
// Combined result processing
274
const summaryQuery = useQueries({
275
queries: [
276
{ queryKey: ['sales'], queryFn: () => fetchSales() },
277
{ queryKey: ['inventory'], queryFn: () => fetchInventory() },
278
{ queryKey: ['orders'], queryFn: () => fetchOrders() }
279
],
280
combine: (results) => ({
281
isLoading: results.some(query => query.isLoading),
282
hasError: results.some(query => query.isError),
283
data: {
284
sales: results[0].data,
285
inventory: results[1].data,
286
orders: results[2].data
287
}
288
})
289
});
290
```
291
292
## Types
293
294
```typescript { .api }
295
// Query option variants
296
interface DefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
297
extends UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
298
initialData: TQueryFnData | (() => TQueryFnData);
299
}
300
301
interface UndefinedInitialQueryOptions<TQueryFnData, TError, TData, TQueryKey>
302
extends UseQueryOptions<TQueryFnData, TError, TData, TQueryKey> {
303
initialData?: undefined | (() => undefined);
304
}
305
306
// Return type variants
307
interface UseQueryDefinedReturnType<TData, TError> extends UseQueryReturnType<TData, TError> {
308
data: Ref<TData>; // Never undefined when initial data is defined
309
}
310
311
// Infinite query specific types
312
interface DefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
313
extends UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> {
314
initialData:
315
| InfiniteData<TQueryFnData, TPageParam>
316
| (() => InfiniteData<TQueryFnData, TPageParam>);
317
}
318
319
interface UndefinedInitialDataInfiniteOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam>
320
extends UseInfiniteQueryOptions<TQueryFnData, TError, TData, TQueryKey, TPageParam> {
321
initialData?: undefined;
322
}
323
324
// Page parameter function types
325
type GetNextPageParamFunction<TQueryFnData, TPageParam> = (
326
lastPage: TQueryFnData,
327
allPages: TQueryFnData[],
328
lastPageParam: TPageParam,
329
allPageParams: TPageParam[]
330
) => TPageParam | undefined | null;
331
332
type GetPreviousPageParamFunction<TQueryFnData, TPageParam> = (
333
firstPage: TQueryFnData,
334
allPages: TQueryFnData[],
335
firstPageParam: TPageParam,
336
allPageParams: TPageParam[]
337
) => TPageParam | undefined | null;
338
339
// Fetch options
340
interface FetchNextPageOptions {
341
cancelRefetch?: boolean;
342
}
343
344
interface FetchPreviousPageOptions {
345
cancelRefetch?: boolean;
346
}
347
```