In this guide, we'll dive into using SWR (Stale-While-Revalidate) in React, a tool that streamlines data fetching, caching, and updating. SWR simplifies the process, allowing you to focus more on your app's functionality.
Installation
To kick things off, you need to install SWR using npm or yarn.
npm i swrBasic Usage
Once SWR is in place, you can employ it to fetch data from an API. Here's how you can do it in a React component:
// Syntax
const { data, error } = useSWR(key, fetcher);If key is
nullthenswrwon't run the fetcher
Here the key can be any function or property. And the fetcher function will receive the key as it's arguement.
import useSWR from 'swr';
function MyComponent() {
const { data, error } = useSWR('/api/data', fetcher);
if (error) return <div>Error loading data</div>;
if (!data) return <div>Loading...</div>;
return <div>Data: {data}</div>;
}
export default MyComponent;We import useSWR from SWR and use it to retrieve data from the '/api/data' endpoint. Also, notice that we've defined a fetcher function that handles the actual HTTP request.
The fetcher Function
The fetcher function is responsible for making the API request and returning the data. Here's what a typical fetcher function might look like:
async function fetcher(url) {
const response = await fetch(url);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}The fetcher function takes a URL, performs the request, and returns the data fetched from that URL. It also handles errors, throwing an error if the response is unsuccessful.
Arguments
key will be passed to fetcher as the argument. So the following 3 expressions are equivalent:
useSWR('/api/user', () => fetcher('/api/user'))
useSWR('/api/user', url => fetcher(url))
useSWR('/api/user', fetcher)Multiple Arguments
const { data: user } = useSWR(['/api/user', token], ([url, token]) => fetchWithToken(url, token))Mutate
mutate(key) or just mutate() will trigger a revalidation same as refetch from react-query.
Mutate Params
- key: same as useSWR's key
- data: data to update the client cache
- options:
{
optimisticData: {}, // data to immediately update the client cache
revalidate: true, // revalidate once the mutation request resolves
rollbackOnError: true, // rollback to previous cache if request rejected
}Data Validation and Revalidation
SWR offers options for data validation and revalidation, allowing you to control when data is refreshed. For instance:
const { data, error } = useSWR('/api/data', fetcher, {
refreshInterval: 60000, // Refresh every 60 seconds
revalidateOnMount: true, // Revalidate when the component mounts
});Error Handling
SWR makes error handling straightforward. It provides an error property in the return object, which allows you to gracefully handle errors. Here's an example:
const { data, error } = useSWR('/api/data', fetcher);
if (error) {
return <div>Error: {error.message}</div>;
}Automatic Revalidation
SWR excels at automatically revalidating data based on a set interval or conditions. You can specify a revalidateOnFocus option to automatically revalidate data when the application regains focus:
const { data } = useSWR('/api/data', fetcher, {
revalidateOnFocus: true, // Revalidate data when the tab regains focus
});This can be particularly useful for real-time applications that rely on up-to-date data.
Prefetch
preload is used to prefetch the resources programmatically and store the results in the cache. preload accepts key and fetcher as the arguments.
It can be called outside of React, inside hooks or in event handlers.
// Preload the resource before rendering the your component,
preload('/api/user', fetcher)
// Preload in effects
useEffect(() => {
preload('/api/user?id=' + userId, fetcher)
}, [userId])
// Preload in event callbacks
<button onClick={() => preload('/api/user?id=' + userId, fetcher)}>Load</button>Dependency Tracking
This is another feature I love. SWR offers the ability to track dependencies. This can help keep your application state consistent. Here's a simplified example:
const { data: userData } = useSWR('/api/user', fetchUser);
const { data: ordersData } = useSWR(() => '/api/orders/' + userData.id, fetchOrders);In this code, when the user data changes, SWR will automatically revalidate the orders data because of the dependency relationship established by the second useSWR call.
Infinite Scrolling
SWR can be used to implement infinite scrolling. It can load more data as the user scrolls down a page, providing a smooth user experience. Here's a simplified example:
const { data, size, setSize } = useSWRInfinite(
(pageIndex, previousPageData) => {
if (previousPageData && !previousPageData.hasMore) return null; // No more data
return `/api/data?page=${pageIndex}`;
},
fetcher
);
const loadMore = () => {
setSize(size + 1);
};
// Render the data and a button to load moreOffline Support
SWR has built-in support for offline data access. If the user loses internet connectivity, SWR will attempt to serve data from the local cache, providing a seamless offline experience.
Why I Prefer SWR Over React Query
Simplicity and Lightweight Nature
SWR is remarkably simple and lightweight. It doesn't introduce much overhead, making it easy to get started quickly. The learning curve is minimal, and you can start fetching data with just a few lines of code. It feels more like a natural extension of React itself.
In contrast, React Query, while feature-rich, may be seen as a bit more complex, with additional concepts to grasp, like query keys and mutations.
Data Fetching with a Hook
SWR's approach to data fetching via a hook, useSWR, fits seamlessly into the React component model. It feels intuitive and aligns with React's principles. With React Query, data fetching is based on hooks as well, but it may require more boilerplate, especially for complex use cases.
