React Data Fetching using React Query & SWR β The 2025 Optimization Guide
Introduction β Why Use React Query or SWR?
Managing API calls with useEffect and useState works fineβuntil it doesn’t. For apps with multiple endpoints, loading spinners, caching, pagination, and real-time updates, you’ll need a smarter data-fetching solution.
React Query and SWR offer powerful abstractions for:
- Caching and background updates
- Refetching, retrying, and invalidation
- Simplified API logic with status tracking
- Automatic sync with server state
In this guide, youβll learn:
- What makes React Query and SWR different
- How to fetch data with each library
- Key features: caching, refetching, and error handling
- Best practices for building scalable data-driven apps
1. What Are React Query and SWR?
| Feature | React Query (TanStack) | SWR (Vercel) |
|---|---|---|
| Purpose | Server-state management | Data fetching & caching |
| API style | useQuery, useMutation | useSWR hook |
| DevTools | Yes (DevTools extension) | Limited |
| Optimistic Updates | Full support | Manual |
| Pagination/Infinite | Built-in | Requires custom logic |
| Query invalidation | Manual & automatic | Not built-in |
2. React Query Setup & Usage
Install:
npm install @tanstack/react-query
Wrap Your App:
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
Basic useQuery Example:
import { useQuery } from '@tanstack/react-query';
const { data, isLoading, error } = useQuery({
queryKey: ['posts'],
queryFn: () => fetch('/api/posts').then(res => res.json())
});
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
Handles loading, error, and refetching out of the box
Perfect for dashboards, filtered lists, and search UIs
3. SWR Setup & Usage
Install:
npm install swr
Basic useSWR Example:
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then(res => res.json());
const { data, error, isLoading } = useSWR('/api/posts', fetcher);
if (isLoading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map(post => <li key={post.id}>{post.title}</li>)}
</ul>
);
Zero-config and dead-simple
Automatically revalidates on window focus and reconnect
4. Refetching & Revalidation
React Query:
const query = useQuery({ queryKey: ['posts'], queryFn: fetchPosts });
// Manual refetch
<button onClick={() => query.refetch()}>Refresh</button>;
SWR:
const { data, mutate } = useSWR('/api/posts', fetcher);
// Trigger revalidation
<button onClick={() => mutate()}>Refresh</button>;
mutate() can also be used for optimistic updates
5. Handling Pagination with React Query
const {
data,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
} = useInfiniteQuery({
queryKey: ['posts'],
queryFn: ({ pageParam = 1 }) =>
fetch(`/api/posts?page=${pageParam}`).then(res => res.json()),
getNextPageParam: (lastPage) => lastPage.nextPage ?? false,
});
Infinite scroll + pagination = built-in
SWR requires manual implementation of pagination logic
6. React Query vs SWR β When to Use What?
| Use Case | Recommended Tool |
|---|---|
| Large-scale apps, dashboards | React Query |
| Simple fetch + cache (small apps) | SWR |
| Infinite queries & mutations | React Query |
| SSR/ISR with Next.js | SWR (Vercel-native) |
| DevTools & advanced debugging | React Query |
Best Practices
Use queryKey to scope & cache data correctly
Use staleTime and cacheTime wisely
Use suspense: true with lazy-loaded components
Use mutate or invalidateQueries to trigger refetch
Wrap logic in custom hooks (e.g., usePosts()) for reusability
Summary β Recap & Next Steps
React Query and SWR simplify and supercharge data fetching in React. They give you better caching, revalidation, and status management than manually using useEffect.
Key Takeaways:
- React Query = robust async state with powerful APIs
- SWR = lightweight caching-focused data hook
- Both handle loading/error states automatically
- Enable features like caching, retry, refetch, and optimistic updates
- Use for REST, GraphQL, or even local cache/mocks
Real-World Relevance:
Used in production by Notion, GitHub, Hashnode, and Vercel to manage UI data with blazing-fast performance and reliability.
FAQ Section
Do I still need Redux with React Query or SWR?
Not for async state. These tools replace Redux for most API-related state.
Can React Query and SWR work with GraphQL?
Yes. Just replace the fetcher with your GraphQL request logic.
What is the main difference between SWR and React Query?
SWR is minimalist and fetch-focused. React Query is feature-rich, built for large apps, with support for caching, pagination, mutations, and devtools.
Can I use these in SSR or SSG apps?
Yes. SWR is optimized for Next.js. React Query also supports Hydration for SSR/SSG.
Is caching automatic in these tools?
Yes. Both tools cache by default and revalidate automatically depending on config.
Share Now :
