Hooks for managing, caching and syncing asynchronous and remote data in React
npx @tessl/cli install tessl/npm-tanstack--react-query@5.87.0Hooks for managing, caching and syncing asynchronous and remote data in React
@tanstack/react-queryTanStack 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.
// Essential hooks for data fetching
import {
useQuery,
useInfiniteQuery,
useMutation,
useQueries
} from '@tanstack/react-query'
// Provider and context
import {
QueryClient,
QueryClientProvider,
QueryClientContext,
useQueryClient
} from '@tanstack/react-query'
// Suspense-enabled hooks
import {
useSuspenseQuery,
useSuspenseInfiniteQuery,
useSuspenseQueries
} from '@tanstack/react-query'
// Utility hooks and state management
import {
useIsFetching,
useIsMutating,
useMutationState,
useQueryErrorResetBoundary,
useIsRestoring,
usePrefetchQuery,
usePrefetchInfiniteQuery
} from '@tanstack/react-query'
// Configuration helpers
import {
queryOptions,
infiniteQueryOptions,
mutationOptions
} from '@tanstack/react-query'
// Components and providers
import {
HydrationBoundary,
QueryErrorResetBoundary,
IsRestoringProvider
} from '@tanstack/react-query'
// Core utility functions
import {
hashKey,
matchQuery,
matchMutation,
keepPreviousData,
skipToken,
CancelledError,
isCancelledError
} from '@tanstack/react-query'
// Core management classes
import {
QueryCache,
MutationCache,
QueryObserver,
InfiniteQueryObserver,
MutationObserver,
QueriesObserver
} from '@tanstack/react-query'
// Manager singletons
import {
focusManager,
onlineManager,
notifyManager
} from '@tanstack/react-query'
// Hydration utilities
import {
dehydrate,
hydrate,
defaultShouldDehydrateQuery,
defaultShouldDehydrateMutation
} from '@tanstack/react-query'
// Core data classes
import {
Query,
Mutation
} from '@tanstack/react-query'import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
// Create a client
const queryClient = new QueryClient()
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your app components */}
</QueryClientProvider>
)
}import { useQuery } from '@tanstack/react-query'
interface User {
id: number
name: string
email: string
}
function UserProfile({ userId }: { userId: number }) {
const {
data: user,
isLoading,
error
} = useQuery<User>({
queryKey: ['user', userId],
queryFn: async () => {
const response = await fetch(`/api/users/${userId}`)
if (!response.ok) {
throw new Error('Failed to fetch user')
}
return response.json()
}
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!user) return null
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
)
}import { useMutation, useQueryClient } from '@tanstack/react-query'
interface CreateUserRequest {
name: string
email: string
}
function CreateUserForm() {
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: async (newUser: CreateUserRequest) => {
const response = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newUser)
})
return response.json()
},
onSuccess: () => {
// Invalidate and refetch user queries
queryClient.invalidateQueries({ queryKey: ['users'] })
}
})
const handleSubmit = (event: React.FormEvent) => {
event.preventDefault()
const formData = new FormData(event.target as HTMLFormElement)
mutation.mutate({
name: formData.get('name') as string,
email: formData.get('email') as string
})
}
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<button type="submit" disabled={mutation.isPending}>
{mutation.isPending ? 'Creating...' : 'Create User'}
</button>
{mutation.error && (
<div>Error: {mutation.error.message}</div>
)}
</form>
)
}import { useInfiniteQuery } from '@tanstack/react-query'
interface UsersPage {
users: User[]
nextCursor?: number
}
function UsersList() {
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading
} = useInfiniteQuery<UsersPage>({
queryKey: ['users'],
queryFn: async ({ pageParam = 0 }) => {
const response = await fetch(`/api/users?cursor=${pageParam}`)
return response.json()
},
initialPageParam: 0,
getNextPageParam: (lastPage) => lastPage.nextCursor
})
if (isLoading) return <div>Loading...</div>
return (
<div>
{data?.pages.map((page, i) => (
<div key={i}>
{page.users.map((user) => (
<div key={user.id}>{user.name}</div>
))}
</div>
))}
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? 'Loading more...'
: hasNextPage
? 'Load More'
: 'Nothing more to load'}
</button>
</div>
)
}This package provides an extensive API with 74+ distinct functions, hooks, and components. The documentation is organized into focused sections:
The foundation of data fetching with caching, background updates, and error handling:
useQuery - Primary hook for fetching and caching datauseInfiniteQuery - Hook for paginated/infinite scroll datauseQueries - Hook for parallel query executionReact Suspense-compatible versions of query hooks:
useSuspenseQuery - Suspense-enabled data fetchinguseSuspenseInfiniteQuery - Suspense-enabled infinite queriesuseSuspenseQueries - Suspense-enabled parallel queriesHooks for data modification with optimistic updates and error handling:
useMutation - Hook for creating, updating, or deleting datauseMutationState - Hook for accessing mutation state across componentsuseIsMutating - Hook for tracking pending mutationsComponents and hooks for managing the QueryClient context:
QueryClientProvider - Provider component for QueryClient contextuseQueryClient - Hook to access the current QueryClientHydrationBoundary - Component for SSR hydrationQueryErrorResetBoundary - Component for error boundary functionalityHelper hooks and utilities for advanced query management:
useIsFetching - Track number of queries currently fetchinguseIsRestoring - Check if queries are being restored from server stateusePrefetchQuery - Prefetch queries before they're neededusePrefetchInfiniteQuery - Prefetch infinite queriesType-safe configuration helpers and option builders:
queryOptions - Helper for creating type-safe query configurationsinfiniteQueryOptions - Helper for infinite query configurationsmutationOptions - Helper for mutation configurationsconst { data } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes
refetchOnWindowFocus: true,
refetchOnReconnect: true
})const mutation = useMutation({
mutationFn: updatePost,
onMutate: async (newPost) => {
// Cancel outgoing refetches
await queryClient.cancelQueries({ queryKey: ['posts'] })
// Snapshot previous value
const previousPosts = queryClient.getQueryData(['posts'])
// Optimistically update
queryClient.setQueryData(['posts'], (old) => [...old, newPost])
return { previousPosts }
},
onError: (err, newPost, context) => {
// Rollback on error
queryClient.setQueryData(['posts'], context.previousPosts)
},
onSettled: () => {
// Always refetch after error or success
queryClient.invalidateQueries({ queryKey: ['posts'] })
}
})const results = useQueries({
queries: [
{ queryKey: ['users'], queryFn: fetchUsers },
{ queryKey: ['posts'], queryFn: fetchPosts },
{ queryKey: ['comments'], queryFn: fetchComments }
],
combine: (results) => ({
data: results.map(result => result.data),
pending: results.some(result => result.isPending)
})
})const { data: user } = useQuery({
queryKey: ['user', userId],
queryFn: () => fetchUser(userId)
})
const { data: posts } = useQuery({
queryKey: ['posts', user?.id],
queryFn: () => fetchUserPosts(user.id),
enabled: !!user?.id // Only run when user is loaded
})The package is built with TypeScript and provides comprehensive type safety:
// Generic type parameters for complete type safety
const { data } = useQuery<
PostsResponse, // TQueryFnData - what the query function returns
Error, // TError - error type
Post[], // TData - final transformed data type
['posts', string] // TQueryKey - query key tuple type
>({
queryKey: ['posts', filter],
queryFn: async ({ queryKey }) => {
const [, filterValue] = queryKey // Fully typed query key access
return fetchPosts(filterValue)
},
select: (data) => data.posts // Transform response to Post[]
})const { data, error, isError } = useQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
throwOnError: false, // Handle errors in component instead of error boundary
retry: (failureCount, error) => {
// Custom retry logic
if (error.status === 404) return false
return failureCount < 3
}
})
if (isError) {
return <div>Error: {error.message}</div>
}// Server-side
import { QueryClient, dehydrate } from '@tanstack/react-query'
const queryClient = new QueryClient()
await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: fetchPosts
})
// Pass dehydrated state to client
const dehydratedState = dehydrate(queryClient)
// Client-side
function App({ dehydratedState }) {
const queryClient = new QueryClient()
return (
<QueryClientProvider client={queryClient}>
<HydrationBoundary state={dehydratedState}>
<Posts />
</HydrationBoundary>
</QueryClientProvider>
)
}// Use query key factories for consistency
const postKeys = {
all: ['posts'] as const,
lists: () => [...postKeys.all, 'list'] as const,
list: (filters: string) => [...postKeys.lists(), { filters }] as const,
details: () => [...postKeys.all, 'detail'] as const,
detail: (id: number) => [...postKeys.details(), id] as const
}
// Usage
const { data } = useQuery({
queryKey: postKeys.detail(postId),
queryFn: () => fetchPost(postId)
})Multiple components calling the same query simultaneously will share the same network request automatically.
Unused query data is automatically garbage collected based on gcTime (default 5 minutes).
Queries automatically refetch in the background when:
This documentation provides comprehensive coverage of TanStack React Query's capabilities for building robust, performant React applications with powerful data fetching and state management.