Data Fetching with SWR and React Query: A Comprehensive Guide
Data fetching is a crucial part of modern web development, especially when building applications that require real-time data updates. With numerous libraries available, developers often find themselves debating between SWR (stale-while-revalidate) and React Query. In this article, we’ll delve deep into both libraries, exploring their features, use cases, and how you can effectively implement them in your React applications.
What is SWR?
SWR is a React Hooks library created by Vercel, designed for data fetching and caching. The name SWR stands for “Stale-While-Revalidate,” which is a cache invalidation strategy that serves stale data while revalidating the data in the background.
Key Features of SWR
- Automatic Caching: SWR caches the response data, reducing redundant network requests.
- Real-time Updates: It provides real-time updates through its revalidation mechanism.
- Built-in support for Suspense: SWR works seamlessly with React’s Suspense, making data loading intuitive.
- TypeScript Support: SWR is fully compatible with TypeScript, enhancing developer experience with type safety.
What is React Query?
React Query is another powerful library for fetching, caching, and synchronizing server state in React applications. It excels in managing server-side data, making it easy to build complex data fetching layers.
Key Features of React Query
- Powerful Query Management: Manage query state, automatic caching, and background fetching.
- Pagination and Infinite Querying: Built-in support for pagination and infinite scrolling.
- Query Invalidations: Fine-grained invalidation and refetching control, allowing for optimal data freshness.
- DevTools: React Query DevTools helps with debug and optimize your queries.
When to Use SWR vs. React Query
Choosing between SWR and React Query can depend on several factors:
- Simplicity: If your application has straightforward data-fetching needs, SWR’s minimalistic approach is a great option.
- Complex State Management: For applications requiring complex server state interactions such as pagination, caching strategies, and query invalidation, React Query shines.
- Real-time Data: Both libraries offer real-time capabilities, but SWR’s focus on revalidation makes it particularly suited for real-time applications.
Getting Started with SWR
Let’s see how to fetch data using SWR in a simple React component.
Installation
npm install swr
Basic Usage
Here’s an example of how to use SWR to fetch a list of users from an API:
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then((res) => res.json());
function UserList() {
const { data, error } = useSWR('https://jsonplaceholder.typicode.com/users', fetcher);
if (error) return <p>Failed to load</p>;
if (!data) return <p>Loading...</p>;
return (
<ul>
{data.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
Getting Started with React Query
Installation
npm install react-query
Basic Usage
Here’s how to fetch the same list of users using React Query:
import { useQuery } from '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();
};
function UserList() {
const { data, error, isLoading } = 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>
);
}
Comparing SWR and React Query: A Side-by-Side Example
Let’s compare both libraries in a more detailed example where we implement data fetching, error handling, and loading states.
Example: Fetching Posts
Using SWR
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then((res) => res.json());
function Posts() {
const { data, error, isLoading } = useSWR('https://jsonplaceholder.typicode.com/posts', fetcher);
if (error) return <p>Error loading posts</p>;
if (!data && isLoading) return <p>Loading posts...</p>;
return (
<div>
<h2>Posts</h2>
<ul>
{data.map(post => (
<li key={post.id}>{post.title}</li>
))}</ul>
</div>
);
}
Using React Query
import { useQuery } from 'react-query';
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();
};
function Posts() {
const { data, error, isLoading } = useQuery('posts', fetchPosts);
if (isLoading) return <p>Loading posts...</p>;
if (error) return <p>Error loading posts: {error.message}</p>;
return (
<div>
<h2>Posts</h2>
<ul>
{data.map(post => (
<li key={post.id}>{post.title}</li>
))}</ul>
</div>
);
}
Handling Mutations
Both libraries provide convenient ways to handle data mutations such as creating, updating, and deleting records.
Mutations with SWR
import useSWR, { mutate } from 'swr';
const postFetcher = (url, data) => fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then((res) => res.json());
function CreatePost() {
const handleSubmit = async (e) => {
e.preventDefault();
const data = { title: e.target.title.value };
// update local data and refetch
const newPost = await postFetcher('https://jsonplaceholder.typicode.com/posts', data);
mutate('https://jsonplaceholder.typicode.com/posts', (posts) => [...posts, newPost], false);
};
return (
<form onSubmit={handleSubmit}>
<input name="title" required />
<button type="submit">Create Post</button>
</form>
);
}
Mutations with React Query
import { useMutation, useQueryClient } from 'react-query';
function CreatePost() {
const queryClient = useQueryClient();
const mutation = useMutation(newPost => {
return fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify(newPost),
headers: {
'Content-Type': 'application/json',
},
}).then((res) => res.json());
}, {
onSuccess: () => {
queryClient.invalidateQueries('posts');
}
});
const handleSubmit = async (e) => {
e.preventDefault();
const data = { title: e.target.title.value };
mutation.mutate(data);
};
return (
<form onSubmit={handleSubmit}>
<input name="title" required />
<button type="submit">Create Post</button>
</form>
);
}
Conclusion
In summary, both SWR and React Query have their unique strengths and cater to different needs in the world of data fetching. SWR excels in simplicity and real-time capabilities, while React Query shines in complex state management and query optimization. By understanding your application’s requirements, you can confidently choose the right data-fetching library for your next React project.
Further Reading and Resources
Happy coding!
