This article summarizes the DEV post “How to Use React Query for Efficient Data Fetching” and focuses on a minimal, production-ready setup.
Why React Query (TanStack Query)
- Handles fetching, caching, retries, background refresh, and deduping.
- Removes
useEffect+ manual loading/error state boilerplate. - Scales to pagination, infinite scroll, and SSR hydration.
3-step setup
- Install:
npm install @tanstack/react-query - Create a client and wrap your app:
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
const App = () => (
<QueryClientProvider client={queryClient}>
<MyComponent />
</QueryClientProvider>
);
- Fetch with
useQuery:
import { useQuery } from "@tanstack/react-query";
function UsersList() {
const { data, isLoading, error } = useQuery({
queryKey: ["users"],
queryFn: () => fetch("/api/users").then((r) => r.json()),
});
if (isLoading) return <p>Loading…</p>;
if (error) return <p>Something went wrong</p>;
return <ul>{data.map((u) => <li key={u.id}>{u.name}</li>)}</ul>;
}
Features you get “for free”
- Auto refetch on window focus/network reconnect.
- Stale-while-revalidate caching with configurable TTLs.
- Retries with exponential backoff for transient failures.
- Query invalidation to refresh related data after mutations.
- Devtools for live inspection of query states.
Power tips
- Prefetch likely-next routes to hide latency (e.g., on hover).
- Use
useInfiniteQueryfor endless scroll; surfacehasNextPage/fetchNextPage. - Pass auth tokens via
queryFnContext; centralize fetcher. - For SSR/Next.js, hydrate with
dehydrate/Hydrateto avoid waterfalls.
Performance guardrails
- Set per-query stale times and retry counts to balance freshness vs. load.
- Log slow queries and cache hit rate; watch INP/LCP when triggering refetches.
- Keep query keys stable and descriptive (e.g.,
["post", postId]).
Bottom line: React Query removes state-management overhead for remote data and delivers faster, more resilient UIs with minimal code.
