React Query (TanStack Query): A Powerful Data Fetching and State Management Library for React
React Query (now called TanStack Query) is an extremely popular data-fetching and state management library for React applications. It simplifies working with remote data by handling the complexities of data fetching, caching, synchronization, and pagination. React Query abstracts away much of the manual process involved in making API requests, storing and updating data, and managing loading states.
TanStack Query helps developers manage server-state in React applications with minimal setup, ensuring a smooth user experience, especially when dealing with asynchronous operations.
1. What is React Query (TanStack Query)?
React Query is a data-fetching and state management tool that helps in simplifying the process of interacting with server-side data in React applications. It abstracts and manages the fetching, caching, synchronization, and background updating of data.
It’s primarily used to manage server-state, which refers to data that comes from a remote server or API, like data from REST APIs, GraphQL, or any other data source.
Key Features:
- Automatic Caching: React Query automatically caches fetched data, which allows for faster subsequent data fetching without extra network requests.
- Automatic Synchronization: It ensures your data stays in sync between the client and server, even when the user switches between pages or revisits the app.
- Background Fetching: React Query can automatically refetch data in the background to ensure the user always has the most up-to-date data.
- Polling and Pagination: React Query supports polling and pagination out of the box, which simplifies these common tasks.
2. Core Concepts of React Query
1. Queries
Queries in React Query are used to fetch data from a server (or any external data source). A query is identified by a unique key, which React Query uses to cache and track the data.
Example:
import { useQuery } from 'react-query';
function fetchPosts() {
return fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json());
}
const Posts = () => {
const { data, error, isLoading } = useQuery('posts', fetchPosts);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error fetching posts</div>;
return (
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
};
-
useQuery
hook fetches the data using thefetchPosts
function. Theposts
string is the unique key, and React Query will cache the fetched data under this key.
2. Mutations
Mutations are used to modify or create data on the server (e.g., POST, PUT, DELETE requests). Like queries, mutations can be tracked and automatically update your state after a successful mutation.
Example:
import { useMutation } from 'react-query';
function createPost(postData) {
return fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify(postData),
headers: { 'Content-Type': 'application/json' },
}).then((response) => response.json());
}
const NewPost = () => {
const mutation = useMutation(createPost);
const handleCreatePost = async () => {
await mutation.mutate({ title: 'New Post', body: 'This is a new post' });
};
return (
<div>
<button onClick={handleCreatePost}>Create Post</button>
{mutation.isLoading ? <p>Creating post...</p> : null}
{mutation.isError ? <p>Error creating post</p> : null}
{mutation.isSuccess ? <p>Post created!</p> : null}
</div>
);
};
-
useMutation
hook is used for operations like creating, updating, or deleting data.
3. Caching
React Query automatically caches the results of queries. This caching allows for faster rendering and avoids making duplicate requests to the server. Cached data is automatically updated when a query is refetched.
You can customize the caching behavior to suit your app’s needs, like setting a cache time or specifying a stale time (the time after which the cached data is considered stale).
Example:
const { data } = useQuery('posts', fetchPosts, {
staleTime: 1000 * 60 * 5, // Cache is fresh for 5 minutes
cacheTime: 1000 * 60 * 30, // Cache persists for 30 minutes
});
4. Pagination
React Query provides built-in support for pagination. You can fetch paginated data with custom page
and limit
parameters, and it will cache the responses appropriately.
Example:
const fetchPage = (page) => fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=10`)
.then((res) => res.json());
const PaginatedPosts = () => {
const [page, setPage] = React.useState(1);
const { data, isLoading, isError } = useQuery(['posts', page], () => fetchPage(page));
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>Error</div>;
return (
<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>
);
};
- The
useQuery
hook is used with an array key (['posts', page]) to fetch paginated data.
3. Installing and Setting Up React Query (TanStack Query)
To use React Query, you'll need to install react-query
(TanStack Query):
npm install react-query
1. Setting Up React Query Provider
To enable React Query in your application, you need to wrap your root component in the QueryClientProvider
to provide the necessary context to the entire app.
import { QueryClient, QueryClientProvider } from 'react-query';
const queryClient = new QueryClient();
const App = () => (
<QueryClientProvider client={queryClient}>
<YourApp />
</QueryClientProvider>
);
-
QueryClient
is the core object of React Query. It manages all the queries and mutations in your app.
4. Advanced Features of React Query
1. Pagination and Infinite Query
React Query supports pagination and infinite scrolling with useInfiniteQuery
, allowing you to handle infinite lists and pagination.
Example:
import { useInfiniteQuery } from 'react-query';
function fetchPostsPage({ pageParam = 1 }) {
return fetch(`https://jsonplaceholder.typicode.com/posts?_page=${pageParam}`)
.then((res) => res.json());
}
const InfinitePosts = () => {
const {
data,
fetchNextPage,
hasNextPage,
isLoading,
isFetchingNextPage,
} = useInfiniteQuery('posts', fetchPostsPage, {
getNextPageParam: (lastPage, allPages) => lastPage.length === 10 ? allPages.length + 1 : false,
});
return (
<div>
{isLoading ? <div>Loading...</div> : null}
{data?.pages.map((page, i) => (
<div key={i}>
{page.map((post) => (
<p key={post.id}>{post.title}</p>
))}
</div>
))}
<button onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage}>
{isFetchingNextPage ? 'Loading more...' : hasNextPage ? 'Load More' : 'No more posts'}
</button>
</div>
);
};
2. Query Invalidations
You can invalidate a query manually using queryClient.invalidateQueries
. This forces a refetch of the data for the specified query key.
Example:
import { useQueryClient } from 'react-query';
const mutation = useMutation(createPost, {
onSuccess: () => {
queryClient.invalidateQueries('posts');
},
});
- This ensures that after creating a new post, the list of posts is refetched automatically.
5. Benefits of Using React Query
1. Simplified Data Fetching
React Query reduces the boilerplate for handling loading, success, and error states, making data fetching easier and more declarative.
2. Automatic Caching
Data fetched is cached by default, reducing unnecessary network requests and speeding up your app.
3. Background Updates
React Query provides background data fetching, ensuring that your app’s data stays fresh even when it's not explicitly refetched.
4. Built-in Pagination and Infinite Queries
Handling pagination and infinite scrolling is simple and efficient with React Query’s built-in hooks.
5. DevTools for Debugging
React Query provides an excellent DevTools interface for inspecting queries, mutations, and their states in real-time.
**6. Conclusion
**
React Query (TanStack Query) provides an efficient and scalable way to handle data-fetching and state management in React applications. With built-in caching, background fetching, pagination, and error handling, React Query makes interacting with server-side data easy and seamless.
Top comments (0)