Mastering React Query: Fetching Data and Managing States Efficiently
Devesh Lashkari
Crafting Scalable Web & Mobile Solutions at Metafic | React | Next.js | Node.js | React Native | Firebase | AWS
Fetching and managing data from the server is a common task in modern web applications. Developers usually use useEffect and useState hooks to fetch the data and manage the component state, but these tools often result in complex and repeated code.?
This is where React Query (also known as Tanstack Query) comes into the picture. React Query makes it easy to fetch, cache, and synchronise the data with minimum effort, allowing developers to focus on their application logic. It reduces boilerplate, improves performance, and enhances user experience, making it a go-to library for managing server state in React applications.
In this article, we’ll see how to use React Query to fetch data from the server using useQuery and handle loading, error and success state more effectively.?
Why Should We Use React Query?
React Query offers various advantages over traditional data-fetching approaches like useEffect and useState hooks. Let’s have a look at why should we consider it:?
React Query simplifies the complexities of fetching, caching and updating the data so we don’t need to manage the isLoading or isError flags manually.
React Query caches the fetched data by default. This means that the subsequent requests for the same data can be served from the stored cache, which results in improving the performance.
React Query always ensures that the Application always has updated data by automatically refetching the outdated queries in the background.
React Query provides options to control how and when the data is prefetched, for example focusing on the window, reconnection of the network or at specific time intervals.
React Query handles the loading, success and error state on its own, So you can fully focus on rendering your UI.
React Query allows you to update the UI before a mutation is confirmed by the server, creating a smooth user experience.
With tools like React Query Devtools, debugging and monitoring queries become easy.
Setting up React Query
Let’s set up React Query in our React Application
npm install @tanstack/react-query
or
yarn add @tanstack/react-query
npm install @tanstack/react-query-devtools
or
yarn add @tanstack/react-query-devtools
We need to wrap our App with the QueryClientProvider component to connect and provide a QueryClient to our application.
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(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.getElementById("root")
);
The setup is done now we can start fetching the data ??
Fetching Data with useQuery
We will create a simple Application to fetch and render the data from a public API. In this article, we will use JSONPlaceholder API to fetch and show the list of posts.?
Create a function to fetch the data from API:?
领英推荐
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();
};
Now import the useQuery hook to fetch the data:
import React from "react";
import { useQuery } from "@tanstack/react-query";
const Posts = () => {
const { data, isLoading, isError, error } = useQuery(["posts"], fetchPosts);
if (isLoading) {
return <p>Loading...</p>;
}
if (isError) {
return <p>Error: {error.message}</p>;
}
return (
<div>
<h1>Posts</h1>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
};
export default Posts;
Understanding the Code
useQuery Parameters:
Returned Values:
Handling States:
Enhancing the User Experience
React Query offers many features to improve the user experience further.
Stale Data and Background Updates
React Query caches data, so it doesn’t refetch unnecessarily. However, it ensures the data is always fresh by fetching it in the background. You can configure how React Query manages this with the staleTime and refetchOnWindowFocus options.
const { data, isLoading, isError, error } = useQuery(["posts"], fetchPosts, {
staleTime: 5000, // Cache data for 5 seconds
refetchOnWindowFocus: false, // Do not refetch when the window regains focus
});
Error Handling with Fallback UI
For finer error handling, you can show a retry button or a fallback UI.
if (isError) {
return (
<div>
<p>Error: {error.message}</p>
<button onClick={() => refetch()}>Retry</button>
</div>
);
}
React Query Devtools
For better debugging and monitoring your queries, you can use React Query Devtools. Add the following code to your app:
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>;
This will give you deep insights about your queries, cache, and background updates.
Final Code
Here’s the complete code:
import React from "react";
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
// Query Client
const queryClient = new QueryClient();
// Fetch Function
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();
};
// Posts Component
const Posts = () => {
const { data, isLoading, isError, error, refetch } = useQuery(["posts"], fetchPosts, {
staleTime: 5000,
refetchOnWindowFocus: false,
});
if (isLoading) {
return <p>Loading...</p>;
}
if (isError) {
return (
<div>
<p>Error: {error.message}</p>
<button onClick={() => refetch()}>Retry</button>
</div>
);
}
return (
<div>
<h1>Posts</h1>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
};
// App Component
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Posts />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
};
export default App;
Conclusion
In this article, we learned about how to use React Query to fetch the data from the server and handle it on the front end.
React Query simplifies data fetching and state management in React apps. With features like caching, background updates, and built-in support for loading and error states, it reduces boilerplate code and enhances performance.
By combining useQuery with proper loading and error handling, you can create user-friendly and efficient applications with ease. Give it a try in your next project!