Fetching and managing API data in React can be tedious, often requiring manual handling of loading states, errors, and caching. Enter React Query, a powerful library that takes the pain out of data fetching and synchronization in React applications.
In this guide, we’ll explore the key features of React Query, how to integrate it into your projects, and best practices for efficient data management.
What is React Query?
React Query is a data-fetching library for React that provides a set of hooks to handle:
- Fetching and caching data.
- Synchronizing server state with the UI.
- Handling background updates and refetching.
Why Use React Query?
- Simplifies asynchronous data fetching.
- Eliminates the need for global state management for server data.
- Built-in caching, pagination, and background updates.
Installing React Query
To get started, install React Query via npm or yarn:
npm install @tanstack/react-query
or
yarn add @tanstack/react-query
You’ll also need the React Query Devtools for debugging:
npm install @tanstack/react-query-devtools
Setting Up React Query
React Query requires a QueryClient
to manage queries. Wrap your application with the QueryClientProvider
in your entry file (e.g., index.js
or App.js
).
Example Setup:
import React from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App";
// Create a QueryClient instance
const queryClient = new QueryClient();
ReactDOM.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>,
document.getElementById("root")
);
Fetching Data with React Query
The useQuery
hook is the primary way to fetch data.
Basic Example:
import { useQuery } from "@tanstack/react-query";
const fetchUsers = async () => {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.json();
};
const Users = () => {
const { data, isLoading, error } = useQuery(["users"], fetchUsers);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default Users;
Key Points:
useQuery
accepts a unique key (["users"]
) and a function to fetch data (fetchUsers
).- It handles loading and error states automatically.
- Cached data is available instantly on refetch.
Advanced Features of React Query
1. Automatic Refetching
React Query automatically refetches data when the window regains focus or the network reconnects. Customize this behavior with the refetchOnWindowFocus
and refetchOnReconnect
options.
useQuery(["users"], fetchUsers, {
refetchOnWindowFocus: false,
});
2. Polling for Updates
Enable polling by setting the refetchInterval
option:
useQuery(["users"], fetchUsers, {
refetchInterval: 5000, // Refetch every 5 seconds
});
3. Mutations with React Query
Use the useMutation
hook to handle data changes like creating, updating, or deleting records.
Example:
import { useMutation, useQueryClient } from "@tanstack/react-query";
const addUser = async (newUser) => {
const response = await fetch("/api/users", {
method: "POST",
body: JSON.stringify(newUser),
});
return response.json();
};
const AddUserForm = () => {
const queryClient = useQueryClient();
const mutation = useMutation(addUser, {
onSuccess: () => {
queryClient.invalidateQueries(["users"]); // Refetch users after mutation
},
});
const handleSubmit = () => {
mutation.mutate({ name: "New User" });
};
return <button onClick={handleSubmit}>Add User</button>;
};
4. Optimistic Updates
React Query allows optimistic updates for a smoother user experience.
useMutation(addUser, {
onMutate: async (newUser) => {
await queryClient.cancelQueries(["users"]);
const previousUsers = queryClient.getQueryData(["users"]);
queryClient.setQueryData(["users"], (old) => [...old, newUser]);
return { previousUsers };
},
onError: (err, newUser, context) => {
queryClient.setQueryData(["users"], context.previousUsers);
},
onSettled: () => {
queryClient.invalidateQueries(["users"]);
},
});
React Query Devtools
React Query Devtools provides an easy way to debug queries. Add the Devtools component to your app:
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
<QueryClientProvider client={queryClient}>
<App />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>;
Best Practices for Using React Query
- Use Unique Query Keys: Always use descriptive and unique keys to avoid conflicts.
- Cache Time and Stale Time:
cacheTime
: How long inactive data is kept in memory.staleTime
: How long data is considered fresh.
- Error Boundaries: Combine React Query with error boundaries for robust error handling.
- Prefetch Data: Use the
queryClient.prefetchQuery
method to load data before it's needed.
When to Use React Query
React Query is ideal for:
- Data-fetching heavy applications.
- Scenarios with server state management needs.
- Projects requiring background updates and caching.
It may not be necessary for simple apps or those already using global state libraries like Redux.
Conclusion
React Query is a game-changer for API data fetching in React applications. With features like automatic caching, refetching, and mutations, it simplifies server-state management, freeing developers to focus on building great user experiences.
Start using React Query today and elevate your React projects to the next level.