Overview
React Query (now TanStack Query) is a powerful library for managing server state. Learn advanced patterns for complex data synchronization scenarios.
Key Concepts
- Query Keys: Organize and invalidate queries
- Background Refetching: Keep data fresh automatically
- Optimistic Updates: Instant UI feedback
- Pagination: Handle large datasets efficiently
- Mutations: Coordinate updates with queries
Setup
npm install @tanstack/react-query
Query Keys Strategy
import { useQuery } from '@tanstack/react-query'
// Good query keys
const queryKeys = {
all: ['users'],
lists: () => [...queryKeys.all, 'list'],
list: (filters: Filters) => [...queryKeys.lists(), { filters }],
details: () => [...queryKeys.all, 'detail'],
detail: (id: number) => [...queryKeys.details(), id]
}
const { data } = useQuery({
queryKey: queryKeys.detail(123),
queryFn: () => fetchUser(123)
})
Optimistic Updates
const mutation = useMutation({
mutationFn: (newName: string) => updateUser(123, { name: newName }),
onMutate: async (newName) => {
await queryClient.cancelQueries({ queryKey: queryKeys.detail(123) })
// Store previous data
const previous = queryClient.getQueryData(queryKeys.detail(123))
// Optimistically update cache
queryClient.setQueryData(queryKeys.detail(123), (old) => ({
...old,
name: newName
}))
return { previous }
},
onError: (err, newName, context) => {
// Revert on error
queryClient.setQueryData(queryKeys.detail(123), context?.previous)
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: queryKeys.detail(123) })
}
})
Infinite Queries
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam = 0 }) => fetchPosts(pageParam),
getNextPageParam: (lastPage) => lastPage.nextCursor
})
return (
<>
{data?.pages.map((page) =>
page.posts.map((post) => <Post key={post.id} {...post} />)
)}
{hasNextPage && (
<button onClick={() => fetchNextPage()}>Load more</button>
)}
</>
)
React Query reduces boilerplate for server state by 80% compared to useState/useEffect.