Hooks for managing, caching and syncing asynchronous and remote data in React
npx @tessl/cli install tessl/npm-tanstack--react-query@5.87.00
# @tanstack/react-query
1
2
**Hooks for managing, caching and syncing asynchronous and remote data in React**
3
4
## Package Information
5
6
- **Package:** `@tanstack/react-query`
7
- **Version:** 5.87.1
8
- **License:** MIT
9
- **Documentation:** https://tanstack.com/query
10
- **Repository:** https://github.com/tanstack/query
11
12
TanStack React Query is a comprehensive React hooks library for managing asynchronous state and remote data fetching. It provides powerful caching and synchronization capabilities with automatic refetching strategies, parallel and dependent queries, mutations with reactive query refetching, multi-layer caching with automatic garbage collection, and advanced features like infinite scroll queries, request cancellation, and React Suspense integration.
13
14
## Core Imports
15
16
```typescript { .api }
17
// Essential hooks for data fetching
18
import {
19
useQuery,
20
useInfiniteQuery,
21
useMutation,
22
useQueries
23
} from '@tanstack/react-query'
24
25
// Provider and context
26
import {
27
QueryClient,
28
QueryClientProvider,
29
QueryClientContext,
30
useQueryClient
31
} from '@tanstack/react-query'
32
33
// Suspense-enabled hooks
34
import {
35
useSuspenseQuery,
36
useSuspenseInfiniteQuery,
37
useSuspenseQueries
38
} from '@tanstack/react-query'
39
40
// Utility hooks and state management
41
import {
42
useIsFetching,
43
useIsMutating,
44
useMutationState,
45
useQueryErrorResetBoundary,
46
useIsRestoring,
47
usePrefetchQuery,
48
usePrefetchInfiniteQuery
49
} from '@tanstack/react-query'
50
51
// Configuration helpers
52
import {
53
queryOptions,
54
infiniteQueryOptions,
55
mutationOptions
56
} from '@tanstack/react-query'
57
58
// Components and providers
59
import {
60
HydrationBoundary,
61
QueryErrorResetBoundary,
62
IsRestoringProvider
63
} from '@tanstack/react-query'
64
65
// Core utility functions
66
import {
67
hashKey,
68
matchQuery,
69
matchMutation,
70
keepPreviousData,
71
skipToken,
72
CancelledError,
73
isCancelledError
74
} from '@tanstack/react-query'
75
76
// Core management classes
77
import {
78
QueryCache,
79
MutationCache,
80
QueryObserver,
81
InfiniteQueryObserver,
82
MutationObserver,
83
QueriesObserver
84
} from '@tanstack/react-query'
85
86
// Manager singletons
87
import {
88
focusManager,
89
onlineManager,
90
notifyManager
91
} from '@tanstack/react-query'
92
93
// Hydration utilities
94
import {
95
dehydrate,
96
hydrate,
97
defaultShouldDehydrateQuery,
98
defaultShouldDehydrateMutation
99
} from '@tanstack/react-query'
100
101
// Core data classes
102
import {
103
Query,
104
Mutation
105
} from '@tanstack/react-query'
106
```
107
108
## Basic Usage
109
110
### Setting Up the Provider
111
112
```typescript { .api }
113
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
114
115
// Create a client
116
const queryClient = new QueryClient()
117
118
function App() {
119
return (
120
<QueryClientProvider client={queryClient}>
121
{/* Your app components */}
122
</QueryClientProvider>
123
)
124
}
125
```
126
127
### Basic Query
128
129
```typescript { .api }
130
import { useQuery } from '@tanstack/react-query'
131
132
interface User {
133
id: number
134
name: string
135
email: string
136
}
137
138
function UserProfile({ userId }: { userId: number }) {
139
const {
140
data: user,
141
isLoading,
142
error
143
} = useQuery<User>({
144
queryKey: ['user', userId],
145
queryFn: async () => {
146
const response = await fetch(`/api/users/${userId}`)
147
if (!response.ok) {
148
throw new Error('Failed to fetch user')
149
}
150
return response.json()
151
}
152
})
153
154
if (isLoading) return <div>Loading...</div>
155
if (error) return <div>Error: {error.message}</div>
156
if (!user) return null
157
158
return (
159
<div>
160
<h1>{user.name}</h1>
161
<p>{user.email}</p>
162
</div>
163
)
164
}
165
```
166
167
### Basic Mutation
168
169
```typescript { .api }
170
import { useMutation, useQueryClient } from '@tanstack/react-query'
171
172
interface CreateUserRequest {
173
name: string
174
email: string
175
}
176
177
function CreateUserForm() {
178
const queryClient = useQueryClient()
179
180
const mutation = useMutation({
181
mutationFn: async (newUser: CreateUserRequest) => {
182
const response = await fetch('/api/users', {
183
method: 'POST',
184
headers: { 'Content-Type': 'application/json' },
185
body: JSON.stringify(newUser)
186
})
187
return response.json()
188
},
189
onSuccess: () => {
190
// Invalidate and refetch user queries
191
queryClient.invalidateQueries({ queryKey: ['users'] })
192
}
193
})
194
195
const handleSubmit = (event: React.FormEvent) => {
196
event.preventDefault()
197
const formData = new FormData(event.target as HTMLFormElement)
198
mutation.mutate({
199
name: formData.get('name') as string,
200
email: formData.get('email') as string
201
})
202
}
203
204
return (
205
<form onSubmit={handleSubmit}>
206
<input name="name" placeholder="Name" required />
207
<input name="email" type="email" placeholder="Email" required />
208
<button type="submit" disabled={mutation.isPending}>
209
{mutation.isPending ? 'Creating...' : 'Create User'}
210
</button>
211
{mutation.error && (
212
<div>Error: {mutation.error.message}</div>
213
)}
214
</form>
215
)
216
}
217
```
218
219
### Infinite Query for Pagination
220
221
```typescript { .api }
222
import { useInfiniteQuery } from '@tanstack/react-query'
223
224
interface UsersPage {
225
users: User[]
226
nextCursor?: number
227
}
228
229
function UsersList() {
230
const {
231
data,
232
fetchNextPage,
233
hasNextPage,
234
isFetchingNextPage,
235
isLoading
236
} = useInfiniteQuery<UsersPage>({
237
queryKey: ['users'],
238
queryFn: async ({ pageParam = 0 }) => {
239
const response = await fetch(`/api/users?cursor=${pageParam}`)
240
return response.json()
241
},
242
initialPageParam: 0,
243
getNextPageParam: (lastPage) => lastPage.nextCursor
244
})
245
246
if (isLoading) return <div>Loading...</div>
247
248
return (
249
<div>
250
{data?.pages.map((page, i) => (
251
<div key={i}>
252
{page.users.map((user) => (
253
<div key={user.id}>{user.name}</div>
254
))}
255
</div>
256
))}
257
<button
258
onClick={() => fetchNextPage()}
259
disabled={!hasNextPage || isFetchingNextPage}
260
>
261
{isFetchingNextPage
262
? 'Loading more...'
263
: hasNextPage
264
? 'Load More'
265
: 'Nothing more to load'}
266
</button>
267
</div>
268
)
269
}
270
```
271
272
## API Documentation
273
274
This package provides an extensive API with 74+ distinct functions, hooks, and components. The documentation is organized into focused sections:
275
276
### [Core Query Hooks](./core-query-hooks.md)
277
The foundation of data fetching with caching, background updates, and error handling:
278
- **`useQuery`** - Primary hook for fetching and caching data
279
- **`useInfiniteQuery`** - Hook for paginated/infinite scroll data
280
- **`useQueries`** - Hook for parallel query execution
281
282
### [Suspense Integration](./suspense-integration.md)
283
React Suspense-compatible versions of query hooks:
284
- **`useSuspenseQuery`** - Suspense-enabled data fetching
285
- **`useSuspenseInfiniteQuery`** - Suspense-enabled infinite queries
286
- **`useSuspenseQueries`** - Suspense-enabled parallel queries
287
288
### [Mutations](./mutations.md)
289
Hooks for data modification with optimistic updates and error handling:
290
- **`useMutation`** - Hook for creating, updating, or deleting data
291
- **`useMutationState`** - Hook for accessing mutation state across components
292
- **`useIsMutating`** - Hook for tracking pending mutations
293
294
### [Provider & Context System](./providers-context.md)
295
Components and hooks for managing the QueryClient context:
296
- **`QueryClientProvider`** - Provider component for QueryClient context
297
- **`useQueryClient`** - Hook to access the current QueryClient
298
- **`HydrationBoundary`** - Component for SSR hydration
299
- **`QueryErrorResetBoundary`** - Component for error boundary functionality
300
301
### [Utility Hooks & Functions](./utilities.md)
302
Helper hooks and utilities for advanced query management:
303
- **`useIsFetching`** - Track number of queries currently fetching
304
- **`useIsRestoring`** - Check if queries are being restored from server state
305
- **`usePrefetchQuery`** - Prefetch queries before they're needed
306
- **`usePrefetchInfiniteQuery`** - Prefetch infinite queries
307
308
### [Configuration & Options](./configuration.md)
309
Type-safe configuration helpers and option builders:
310
- **`queryOptions`** - Helper for creating type-safe query configurations
311
- **`infiniteQueryOptions`** - Helper for infinite query configurations
312
- **`mutationOptions`** - Helper for mutation configurations
313
314
## Key Features
315
316
### Automatic Caching & Background Updates
317
```typescript { .api }
318
const { data } = useQuery({
319
queryKey: ['posts'],
320
queryFn: fetchPosts,
321
staleTime: 5 * 60 * 1000, // 5 minutes
322
gcTime: 10 * 60 * 1000, // 10 minutes
323
refetchOnWindowFocus: true,
324
refetchOnReconnect: true
325
})
326
```
327
328
### Optimistic Updates
329
```typescript { .api }
330
const mutation = useMutation({
331
mutationFn: updatePost,
332
onMutate: async (newPost) => {
333
// Cancel outgoing refetches
334
await queryClient.cancelQueries({ queryKey: ['posts'] })
335
336
// Snapshot previous value
337
const previousPosts = queryClient.getQueryData(['posts'])
338
339
// Optimistically update
340
queryClient.setQueryData(['posts'], (old) => [...old, newPost])
341
342
return { previousPosts }
343
},
344
onError: (err, newPost, context) => {
345
// Rollback on error
346
queryClient.setQueryData(['posts'], context.previousPosts)
347
},
348
onSettled: () => {
349
// Always refetch after error or success
350
queryClient.invalidateQueries({ queryKey: ['posts'] })
351
}
352
})
353
```
354
355
### Parallel Queries
356
```typescript { .api }
357
const results = useQueries({
358
queries: [
359
{ queryKey: ['users'], queryFn: fetchUsers },
360
{ queryKey: ['posts'], queryFn: fetchPosts },
361
{ queryKey: ['comments'], queryFn: fetchComments }
362
],
363
combine: (results) => ({
364
data: results.map(result => result.data),
365
pending: results.some(result => result.isPending)
366
})
367
})
368
```
369
370
### Dependent Queries
371
```typescript { .api }
372
const { data: user } = useQuery({
373
queryKey: ['user', userId],
374
queryFn: () => fetchUser(userId)
375
})
376
377
const { data: posts } = useQuery({
378
queryKey: ['posts', user?.id],
379
queryFn: () => fetchUserPosts(user.id),
380
enabled: !!user?.id // Only run when user is loaded
381
})
382
```
383
384
## TypeScript Support
385
386
The package is built with TypeScript and provides comprehensive type safety:
387
388
```typescript { .api }
389
// Generic type parameters for complete type safety
390
const { data } = useQuery<
391
PostsResponse, // TQueryFnData - what the query function returns
392
Error, // TError - error type
393
Post[], // TData - final transformed data type
394
['posts', string] // TQueryKey - query key tuple type
395
>({
396
queryKey: ['posts', filter],
397
queryFn: async ({ queryKey }) => {
398
const [, filterValue] = queryKey // Fully typed query key access
399
return fetchPosts(filterValue)
400
},
401
select: (data) => data.posts // Transform response to Post[]
402
})
403
```
404
405
## Error Handling
406
407
```typescript { .api }
408
const { data, error, isError } = useQuery({
409
queryKey: ['posts'],
410
queryFn: fetchPosts,
411
throwOnError: false, // Handle errors in component instead of error boundary
412
retry: (failureCount, error) => {
413
// Custom retry logic
414
if (error.status === 404) return false
415
return failureCount < 3
416
}
417
})
418
419
if (isError) {
420
return <div>Error: {error.message}</div>
421
}
422
```
423
424
## Server-Side Rendering (SSR)
425
426
```typescript { .api }
427
// Server-side
428
import { QueryClient, dehydrate } from '@tanstack/react-query'
429
430
const queryClient = new QueryClient()
431
await queryClient.prefetchQuery({
432
queryKey: ['posts'],
433
queryFn: fetchPosts
434
})
435
436
// Pass dehydrated state to client
437
const dehydratedState = dehydrate(queryClient)
438
439
// Client-side
440
function App({ dehydratedState }) {
441
const queryClient = new QueryClient()
442
443
return (
444
<QueryClientProvider client={queryClient}>
445
<HydrationBoundary state={dehydratedState}>
446
<Posts />
447
</HydrationBoundary>
448
</QueryClientProvider>
449
)
450
}
451
```
452
453
## Performance & Best Practices
454
455
### Query Key Management
456
```typescript { .api }
457
// Use query key factories for consistency
458
const postKeys = {
459
all: ['posts'] as const,
460
lists: () => [...postKeys.all, 'list'] as const,
461
list: (filters: string) => [...postKeys.lists(), { filters }] as const,
462
details: () => [...postKeys.all, 'detail'] as const,
463
detail: (id: number) => [...postKeys.details(), id] as const
464
}
465
466
// Usage
467
const { data } = useQuery({
468
queryKey: postKeys.detail(postId),
469
queryFn: () => fetchPost(postId)
470
})
471
```
472
473
### Request Deduplication
474
Multiple components calling the same query simultaneously will share the same network request automatically.
475
476
### Garbage Collection
477
Unused query data is automatically garbage collected based on `gcTime` (default 5 minutes).
478
479
### Background Updates
480
Queries automatically refetch in the background when:
481
- Window regains focus
482
- Network reconnects
483
- Query becomes stale
484
- Manual invalidation occurs
485
486
This documentation provides comprehensive coverage of TanStack React Query's capabilities for building robust, performant React applications with powerful data fetching and state management.