TanStack Query (formerly React Query) is a powerful and flexible data-fetching library for JavaScript and TypeScript applications. It provides efficient tools to manage server state, including caching, synchronization, and background updates. By eliminating the need for boilerplate code, TanStack Query allows developers to focus on building features rather than managing API calls manually.
Core Concepts
1. Query
A query represents a piece of asynchronous data that can be fetched, cached, and synchronized with the server. Queries are identified by unique query keys and are automatically managed by TanStack Query.
import { useQuery } from '@tanstack/react-query'; const fetchData = async () => { const response = await fetch('/api/data'); return response.json(); }; const MyComponent = () => { const { data, isLoading, error } = useQuery(['data'], fetchData); if (isLoading) return <div>Loading...</div>; if (error) return <div>Error loading data</div>; return <div>{JSON.stringify(data)}</div>; };
2. Mutation
Mutations are used to modify data on the server (e.g., creating, updating, or deleting resources). They are optimized to handle optimistic updates, rollback on failure, and cache invalidation.
import { useMutation, useQueryClient } from '@tanstack/react-query'; const postData = async (newData) => { const response = await fetch('/api/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(newData), }); return response.json(); }; const MyComponent = () => { const queryClient = useQueryClient(); const mutation = useMutation(postData, { onSuccess: () => { queryClient.invalidateQueries(['data']); }, }); return ( <button onClick={() => { mutation.mutate({ name: 'New Item' }); }} > Add Item </button> ); };
3. Query Keys
Query keys uniquely identify queries. They can be simple strings or structured arrays with additional context.
useQuery(['todos'], fetchTodos); useQuery(['todos', { status: 'completed' }], fetchFilteredTodos);
4. Query Client
The Query Client is the core utility used to manage queries, mutations, and their configuration. It provides methods to manipulate query cache, invalidate queries, and refetch data.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; const queryClient = new QueryClient(); const App = () => ( <QueryClientProvider client={queryClient}> <MyComponent /> </QueryClientProvider> );
Key Methods and Options
useQuery
● Purpose: Fetch and cache data.
● Options:
○ queryKey: Unique identifier for the query.
○ queryFn: Function to fetch the data.
○ enabled: Boolean to enable or disable automatic queries.
○ staleTime: Time in milliseconds before the query becomes stale. ○ cacheTime: Time in milliseconds to keep data in cache.
○ retry: Number of retries on failure (default is 3).
const { data, isLoading, error } = useQuery( ['todos'], fetchTodos, { enabled: true, staleTime: 60000, cacheTime: 300000, retry: 2, });
useMutation
● Purpose: Manage server-modifying actions.
● Options:
○ mutationFn: Function to execute the mutation.
○ onSuccess: Callback after a successful mutation.
○ onError: Callback after a failed mutation.
○ onSettled: Callback after a mutation completes (success or failure).
const mutation = useMutation(postData, { onSuccess: () => { console.log('Data successfully posted!'); }, onError: (error) => { console.error('An error occurred:', error); }, });
useInfiniteQuery
● Purpose: Fetch paginated data.
const { data, fetchNextPage, hasNextPage } = useInfiniteQuery(['todos'], fetchPaginatedTodos, { getNextPageParam: (lastPage, allPages) => lastPage.nextCursor, });
prefetchQuery
● Purpose: Preload data without rendering.
queryClient.prefetchQuery(['todos'], fetchTodos);
refetchQueries
● Purpose: Immediately refetch queries.
queryClient.refetchQueries(['todos']);
Advanced Topics
1. Devtools
TanStack Query Devtools provide a visual interface to inspect and debug queries and mutations.
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; <QueryClientProvider client={queryClient}> <App /> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; <QueryClientProvider client={queryClient}> <App /> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider>
2. SSR and Hydration
TanStack Query supports Server-Side Rendering (SSR) and hydration for better SEO and performance.
import { Hydrate } from '@tanstack/react-query'; <QueryClientProvider client={queryClient}> <Hydrate state={dehydratedState}> <App /> </Hydrate> </QueryClientProvider> import { Hydrate } from '@tanstack/react-query'; <QueryClientProvider client={queryClient}> <Hydrate state={dehydratedState}> <App /> </Hydrate> </QueryClientProvider>
3. Error Handling
Centralized error handling using Error Boundaries or global handlers.
const queryClient = new QueryClient({ defaultOptions: { queries: { onError: (error) => console.error(error), }, }, }); const queryClient = new QueryClient({ defaultOptions: { queries: { onError: (error) => console.error(error), }, }, });
Conclusion
TanStack Query simplifies data fetching and state management in modern applications. Its robust feature set, including caching, synchronization, and mutation handling, makes it a go-to solution for managing server state efficiently. By adopting TanStack Query, developers can create performant and maintainable applications while reducing boilerplate and complexity.
For more details, explore the official documentation.