How to Master Data Fetching in React Using TanStack Query


Data fetching is a critical aspect of modern web applications, and managing it efficiently can be challenging. Enter TanStack Query (formerly known as React Query), a powerful library that simplifies data fetching, caching, synchronization, and server-state management in React applications. In this article, we’ll explore how TanStack Query can revolutionize your data-fetching workflow and provide practical examples to get you started.
What is TanStack Query?
TanStack Query is a data-fetching library for React that provides a declarative and intuitive API for managing server state. It handles caching, background updates, stale data, pagination, and more, allowing developers to focus on building features rather than managing complex data-fetching logic.
Key Features:
Automatic Caching: TanStack Query caches data automatically and intelligently refetches it when needed.
Background Updates: It keeps your UI up-to-date by refetching data in the background.
Devtools: Built-in devtools help you debug and inspect queries.
Pagination and Infinite Queries: Easily handle paginated or infinite data.
Optimistic Updates: Update the UI optimistically before the server responds.
TypeScript Support: First-class TypeScript support for type-safe development.
Why Use TanStack Query?
Traditional data-fetching approaches in React often involve writing repetitive boilerplate code for fetching, caching, and updating data. TanStack Query abstracts away these complexities, providing a streamlined and efficient way to manage server state. Here’s why you should consider using it:
Reduced Boilerplate: No need to write custom hooks or manage loading/error states manually.
Improved Performance: Intelligent caching and background updates ensure optimal performance.
Better Developer Experience: Built-in tools and a simple API make development faster and more enjoyable.
Scalability: Designed to handle complex data-fetching scenarios in large applications.
Getting Started with TanStack Query
Installation:
To get started, install TanStack Query and its dev tools (optional but recommended):
npm install @tanstack/react-query @tanstack/react-query-devtools
Setting Up the Query Client:
Wrap your application with the QueryClientProvider
and create a QueryClient
instance.
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* Your application components */}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
Basic Data Fetching with TanStack Query
TanStack Query uses queries to fetch data. A query is a declarative dependency on an asynchronous data source. Here’s how to fetch data from an API:
Example: Fetching a List of Posts
import { useQuery } from '@tanstack/react-query';
const fetchPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
};
function Posts() {
const { data, isLoading, isError, error } = useQuery(['posts'], fetchPosts);
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error: {error.message}</div>;
return (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Explanation:
useQuery
: A hook that fetches and manages the data.Query Key: The
['posts']
array is a unique identifier for the query. It can be used for caching and refetching.States:
isLoading
,isError
, anderror
provide information about the query’s status.
Advanced Features
1. Pagination
TanStack Query makes it easy to handle paginated data using the useQuery
hook.
const fetchPosts = async (page) => {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=10`);
return response.json();
};
function Posts() {
const [page, setPage] = useState(1);
const { data, isLoading } = useQuery(['posts', page], () => fetchPosts(page));
return (
<div>
{isLoading ? (
<div>Loading...</div>
) : (
<>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
<button onClick={() => setPage((prev) => prev - 1)} disabled={page === 1}>
Previous
</button>
<button onClick={() => setPage((prev) => prev + 1)}>Next</button>
</>
)}
</div>
);
}
2. Mutations (Updating Data)
TanStack Query uses mutations to update server data. For example, creating a new post:
import { useMutation, useQueryClient } from '@tanstack/react-query';
const createPost = async (newPost) => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify(newPost),
});
return response.json();
};
function AddPost() {
const queryClient = useQueryClient();
const mutation = useMutation(createPost, {
onSuccess: () => {
queryClient.invalidateQueries(['posts']); // Refetch posts after mutation
},
});
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const newPost = { title: formData.get('title'), body: formData.get('body') };
mutation.mutate(newPost);
};
return (
<form onSubmit={handleSubmit}>
<input name="title" placeholder="Title" />
<textarea name="body" placeholder="Body" />
<button type="submit">Add Post</button>
</form>
);
}
3. Infinite Queries
For infinite loading scenarios, use the useInfiniteQuery
hook.
import { useInfiniteQuery } from '@tanstack/react-query';
const fetchPosts = async ({ pageParam = 1 }) => {
const response = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}&_limit=10`);
return response.json();
};
function Posts() {
const { data, fetchNextPage, hasNextPage, isLoading } = useInfiniteQuery(
['posts'],
fetchPosts,
{
getNextPageParam: (lastPage, allPages) => allPages.length + 1,
}
);
return (
<div>
{isLoading ? (
<div>Loading...</div>
) : (
<>
<ul>
{data.pages.map((page) =>
page.map((post) => <li key={post.id}>{post.title}</li>)
)}
</ul>
{hasNextPage && <button onClick={() => fetchNextPage()}>Load More</button>}
</>
)}
</div>
);
}
Best Practices
Use Query Keys Effectively: Query keys should uniquely identify the data being fetched. Use arrays for complex keys.
Leverage Devtools: The React Query Devtools are invaluable for debugging and optimizing queries.
Optimize Performance: Use
staleTime
andcacheTime
to control how long data is considered fresh or cached.Handle Errors Gracefully: Always handle loading and error states to provide a smooth user experience.
Conclusion
TanStack Query is a game-changer for data fetching in React applications. Its intuitive API, powerful features, and excellent developer experience make it a must-have tool for modern web development. Whether you’re building a small app or a large-scale application, TanStack Query simplifies data management and helps you deliver a better user experience.
Start integrating TanStack Query into your React projects today, and unlock the full potential of efficient and scalable data fetching!
Subscribe to my newsletter
Read articles from Tamiz Uddin directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Tamiz Uddin
Tamiz Uddin
Experienced Full-Stack Developer specializing in MongoDB, Express, React, Next.js, and Node.js. Experienced in developing real-time video calling and messaging applications using WebRTC & Socket.IO. Skilled in building scalable, high-performance web applications with optimized UI/UX. A strong collaborator with product and design teams, ensuring seamless and innovative user experiences.