React Query is a library for fetching, caching, and synchronizing server data in React applications.
npm i @tanstack/react-query
npm i @tanstack/react-query-devtools
- Why React Query
- Setting Up React Query
- The useQuery hook
- The useMutation Hook
- The useQueryClient Hook
- The defaultOptions Object
- Prefetching
- React Query Features
- Simplified Data Fetching: React Query abstracts the complexity of data fetching, reducing boilerplate code.
- Caching: It provides built-in caching, which can significantly improve performance by avoiding unnecessary network requests.
- Synchronization: React Query ensures that your data is always up-to-date with minimal effort.
- Server State Management: It helps manage server state efficiently, keeping it in sync with the client state.
- Error Handling: It provides robust error handling and retries for failed requests.
Create a QueryClient instance and wrap your component tree with the QueryClientProvider.
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient({
defaultOptions: { queries: { staleTime: 0 } },
});
function App() {
return (
<QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
);
}QueryClient accepts an object with options. The { staleTime: 0 } option defines how long the fetched data is considered fresh.
The useQuery hook is used to fetch and manage data.
import { useQuery } from "@tanstack/react-query";
async function getData() {
const { data } = await axios.get("api/data");
return data;
}
function MyComponent() {
const { data, error, isPending } = useQuery({
queryKey: ["data"],
queryFn: getData,
});
if (isPending) return <Spinner />;
if (error) return <Error error={error} />;
return <List data={data} />;
}queryKey- unique identifier for your query.queryFn- function that fetches the data.
Mutations are used to create, update, or delete data. The useMutation hook is used for this purpose.
useMutation returns a mutate function that calls the function we provide at mutationFn.
The onSuccess and onError functions will run accordingly based on the response.
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { updateItem as updateApi } from "./apis/updateItem";
function useUpdateItem() {
const queryClient = useQueryClient();
const { mutate: updateItem, isPending } = useMutation({
mutationFn: (id) => updateApi(id),
onSuccess: (data) => queryClient.invalidateQueries({ queryKey: ["data"] }),
onError: (err) => console.log(err),
});
return { updateItem, isPending };
}
function Item() {
const { updateItem, isPending } = useUpdateItem();
return (
<button onClick={() => updateItem(23)} disabled={isPending}>
Update Item
</button>
);
}The useQueryClient hook provides access to the QueryClient instance.
import { useQueryClient } from "@tanstack/react-query";
function Component() {
const queryClient = useQueryClient();
}// 1. Invalidate queries to refetch them the next time they are used.
queryClient.invalidateQueries("data");
// 2. Manually refetch queries.
queryClient.refetchQueries("data");
// 3. Get the current cached data for a query.
queryClient.getQueryData("data");
// 4. Manually set the cached data for a query.
queryClient.setQueryData("data", newData);
// 5. Remove queries from the cache.
queryClient.removeQueries("data");
// 6. Reset the state of queries to their initial state.
queryClient.resetQueries("data");The defaultOptions object is used to set global defaults for all queries or mutations within your application. It has two main properties: queries and mutations.
const options = { defaultOptions: { queries: {}, mutations: {} } };-
staleTime: The amount of time in milliseconds that a query's data is considered fresh. SettingstaleTimeto0means that the data is immediately considered stale and will be refetched on every mount. -
cacheTime: The amount of time in milliseconds that unused or inactive query data remains in the cache. The default is 5 minutes. After this time, the data is garbage collected. -
refetchOnWindowFocus: Iftrue, the query will refetch on window focus. The default istrue. -
refetchOnReconnect: Iftrue, the query will refetch on reconnect. The default istrue. -
refetchOnMount: Iftrue, the query will refetch on component mount. The default istrue. -
retry: The number of times to retry a failed query before throwing an error. The default is3. -
retryDelay: The delay between retry attempts in milliseconds. The default is an exponential backoff function. -
enabled: Iffalse, the query will not automatically run. This can be useful for dependent queries that should only run under certain conditions. -
suspense: Iftrue, the query will be used with React's Suspense. The default isfalse. -
initialData: Initial data to use while the query is being fetched. This can be useful for server-side rendering or providing an initial cache state.
-
retry: The number of times to retry a failed mutation before throwing an error. The default is 0 (no retries). -
retryDelay: The delay between retry attempts in milliseconds. This can be a static value or a function that receives the retry attempt index and returns the delay. -
onMutate: A function that fires before the mutation function is fired and is passed the same variables the mutation function would receive. Useful for optimistic updates. -
onError: A function that fires if the mutation encounters an error. It receives the error, the variables that were passed to the mutation, and the mutation context. -
onSuccess: A function that fires if the mutation is successful. It receives the data returned from the mutation, the variables that were passed to the mutation, and the mutation context. -
onSettled: A function that fires when the mutation is either successfully fetched or encounters an error. It receives the data or error, the variables that were passed to the mutation, and the mutation context.
useQuery({
queryKey: ["data"],
queryFn: getData,
initialData: "Important Data",
retry: 2,
retryDelay: 2000,
});useMutation({
mutationFn: (id) => updateApi(id),
onSuccess: (data) => console.log("Success!")
onError: (err) => console.log(err.message),
onSettled: () => console.log("Settled"),
});Prefetching in React Query is a technique used to load data into the query cache before it is needed, improving the user experience by reducing perceived load times. This is especially useful for data that you know will be needed soon, such as when navigating between pages or displaying related data.
queryClient.prefetchQuery("data", getData);React Query offers a range of features that simplify the process of data fetching and state management in React applications.
React Query caches the data it fetches, which means that subsequent requests for the same data can be served from the cache instead of making a network request. This reduces the load on your server and speeds up the application for the user.
The cached data is automatically managed by React Query, and it can be configured to expire after a certain period or based on certain conditions.
React Query simplifies the handling of loading and error states in your application. When you use the useQuery hook, it provides isPending and error states out of the box.
This means you can easily display loading spinners or error messages without having to write custom logic for each data fetch.
React Query ensures that your data stays up-to-date by automatically re-fetching data under certain conditions, such as: when the component mounts, when the window is refocused, when the network is reconnected.
This automatic re-fetching keeps your UI in sync with the latest data from the server without requiring manual intervention.
Pre-fetching allows you to fetch data before it is needed, which can improve the user experience by reducing loading times (fetch data in the background and store it in the cache).
This is particularly useful for scenarios where you know the user will navigate to a certain part of the application and you want to have the data ready beforehand.
React Query makes it simple to update remote state using mutations. It provides useful hooks that allow you to perform create, update, or delete operations on the server and automatically update the local cache based on the result.
This ensures that your local state remains consistent with the remote state, reducing the complexity of managing server interactions.
React Query provides built-in support for offline scenarios. When the application detects that it is offline, it will not attempt to fetch data from the server. Instead, it can use the cached data to continue functioning. Once the connection is restored, it can automatically re-fetch the latest data. This ensures a smooth user experience even in environments with intermittent connectivity.