Data fetching is one of the most critical parts of building modern React applications. It involves retrieving data from external sources like APIs and databases and displaying it in the app. However, handling asynchronous data fetching manually in React can be complex due to issues like caching, synchronization, error handling, and ensuring optimal performance. React Query simplifies this process by providing a powerful set of hooks to manage server state and asynchronous data fetching in React apps.
React Query is a library for server state management in React applications. Unlike React’s built-in state management, which is focused on UI state (e.g., form inputs, component visibility), React Query handles server state, which involves data fetched from an external source (such as an API) and is subject to synchronization, caching, and updating.
useQuery
, useMutation
).To use React Query in your React project, you need to install the library:
npm install @tanstack/react-query
In addition, to make sure the React Query Devtools are available for debugging and monitoring queries, you can install the React Query Devtools package:
npm install @tanstack/react-query-devtools
React Query requires a QueryClient to manage all queries in the application. You must wrap your app inside a QueryClientProvider to enable React Query functionalities.
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import App from './App';
const queryClient = new QueryClient();
ReactDOM.render(
,
document.getElementById('root')
);
The useQuery
hook is the heart of React Query’s data fetching capabilities. It is used to fetch data asynchronously from a server and manage its caching, loading, and error states.
Here’s an example of using useQuery
to fetch data from a JSON placeholder API.
// src/components/Posts.js
import React from 'react';
import { useQuery } from '@tanstack/react-query';
const fetchPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
};
function Posts() {
const { data, error, isLoading } = useQuery(['posts'], fetchPosts);
if (isLoading) return Loading...
;
if (error) return An error occurred: {error.message}
;
return (
Posts
{data.map(post => (
- {post.title}
))}
);
}
export default Posts;
useQuery(['posts'], fetchPosts)
: The useQuery
hook takes two arguments: a query key (here, 'posts'
) and a function (fetchPosts
) that fetches the data.isLoading
: A boolean indicating if the query is still in the loading state.error
: Contains the error object if the query failed.data
: Contains the fetched data once the query is successful.React Query provides automatic caching for your data. Once data is fetched, it is stored in a cache, and subsequent requests for the same data will return the cached version unless explicitly refetched.
React Query’s cache management is intelligent. If the same query is requested again while the data is still fresh, React Query will serve the data from the cache instead of refetching it from the server.
function CachedPosts() {
const { data, isFetching } = useQuery(['posts'], fetchPosts);
return (
{isFetching && Updating posts...
}
{data.map(post => (
- {post.title}
))}
);
}
isFetching
: Indicates whether a background refetch is in progress (i.e., the query is being updated from the server).By default, React Query considers data “stale” after it has been cached for 5 minutes (300,000 milliseconds). Once the data is stale, React Query automatically refetches it when you revisit the component.
You can customize how long React Query should consider the data fresh using the staleTime
option.
function StalePosts() {
const { data, isFetching } = useQuery(['posts'], fetchPosts, {
staleTime: 10000, // Data will be considered fresh for 10 seconds
});
return (
{isFetching && Updating posts...
}
{data.map(post => (
- {post.title}
))}
);
}
staleTime: 10000
: Sets the stale time to 10 seconds, meaning the data will be considered fresh for 10 seconds. After that, a background refetch will occur when the component is mounted.Handling errors is a crucial part of any data-fetching strategy. React Query provides built-in mechanisms to manage errors seamlessly.
React Query automatically returns an error
object if the query fails.
function PostsWithError() {
const { data, error, isLoading } = useQuery(['posts'], async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/invalid-url');
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
});
if (isLoading) return Loading...
;
if (error) return Error: {error.message}
;
return (
{data.map(post => (
- {post.title}
))}
);
}
error
object with a message. The UI can then display the error message appropriately.React Query offers built-in support for paginated data, which is common when dealing with large datasets that need to be fetched incrementally.
To implement pagination, React Query provides options for fetching the next set of data when required.
function PaginatedPosts() {
const [page, setPage] = React.useState(1);
const fetchPosts = async ({ queryKey }) => {
const [_key, page] = queryKey;
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts?_page=${page}`
);
return res.json();
};
const { data, isFetching, isPreviousData } = useQuery(
['posts', page],
fetchPosts,
{ keepPreviousData: true }
);
return (
{isFetching && Loading posts...
}
{data.map(post => (
- {post.title}
))}
);
}
page
: Represents the current page number.keepPreviousData
: Ensures the previous page’s data remains while fetching the next page’s data.queryKey
: The query key now includes page
, so React Query refetches data when the page changes.React Query revolutionizes how data fetching and server-side state management are handled in React applications. From automatic caching, background refetching, and pagination to built-in error handling, it provides a robust, declarative API that greatly simplifies the process. Using React Query allows you to focus more on building the user interface and less on the intricacies of data management, which improves the maintainability and performance of your React applications. Happy Coding!❤️