SWR, a React-friendly API used both stand-alone and by Vercel's Next.js platform, is a caching data manager. It can fetch anything, owing to the API's fetcher
delegating network querying API. It provides intelligent data caching, pagination, support for the React Suspense
component, and a number of other features.
In this article I'll show you a simple interaction with a dynamically changing NodeJS RESTful data resource via Next.js, using SWR to fetch, cache and refresh the data.
Motivations
Data from server resources frequently change after being fetched by a client. Many times your application needs to keep its data up to date. For example, changing weather forecasts, financial data feeds, live dashboards, and many other services rely on auto refreshed data.
Rather than roll your own feature using your own timers and cache busting tools, you can rely on SWR to manage these feeds for you.
SWR for Dynamic Fetching
With SWR (which stands for "stale while revalidate"), a data fetching API (such as Fetch, Axios, or even GraphQL) is wrapped with a "Fetcher" facade. This facade is called upon by the SWR hook (useSWR
) to bind data functionally to your React components, which is then kept up to date based on settings in the SWR configuration API.
Let's start by defining a network feed to monitor, using the useSWR
hook. My arbitrary example, available at GitHub, uses a NodeJS resource server to serve up quotes to a React app:
export default function SwrDemoComponent() { const { data, error } = useSWR('/api/cms/demo'); return { { !error && data && <p>Data! {data}</p> } }; };
As with other hooks, the useSWR
hook returns multiple properties to work with:
data
– the data fetched by the hookerror
– any error that results from fetching the dataisValidating
– a boolean to show that the fetcher is activemutate
– a method to call to invalidate any cache and request a data refresh from SWR-fetched data
Building a data fetcher
Here is our fetcher API, used when configuring SWR. It fetches the resource using the browser's Fetch API, which in Next.js is backed up by a server-side equivalent:
export async function fetcher (resource: string) { let result; try { result = await fetch(resource); } catch (e) { console.log('***** Problem with fetch that results in an exception'); console.error(e); throw new Error('Invalid Response'); } if (result.ok) { try { return await result.json(); } catch (e) { console.log('***** Problem with JSON payload', e); throw 'Result OK but JSON borked'; } } else { console.log('****** Result ! OK', result.status, result.statusText); throw result.statusText; } }
In the fetcher above, we handle several error conditions. For status errors, we unpack and throw an error containing the statusText
property of the response. For invalid data responses, we throw an error with the message that the JSON is invalid. Finally, if the network stack fails (i.e. the server is offline) we also handle that error as well as an "Invalid Response".
Installing the fetcher in SWR
Fetchers can be used directly from the useSWR
hook:
const { data, error } = useSWR('/api/foobar', fetcher);
Rather than attaching the fetcher to every hook, we can use a component to wrap all useSWR
usages and attach the middleware there. This example uses the Next.js page template file, _app.tsx
, to install the fetcher for the entire application, and also sets some global settings:
import '../styles/globals.css' import type { AppProps } from 'next/app' import { fetcher as myFetcher } from '../shared/fetcher'; import { SWRConfig } from 'swr'; function MyApp({ Component, pageProps }: AppProps) { return ( <SWRConfig value={{ refreshInterval: 10000, fetcher: myFetcher }}> <Component {...pageProps} /> </SWRConfig> ); } export default MyApp
SWR options
Yes, the example above sets a 10 second auto-refresh interval. By default, SWR will reload data when:
- The user switches tabs in a browser and then switches back to the application containing the SWR hook
- the user goes offline and then online again
Adding the refresh interval makes it possible for data to be displayed once cached, and to be replaced once a new payload appears on the network, within the interval.
Other SWR options include:
suspense
– enable ReactSuspense
supportrevalidateIfStale
– once a component mounts, by default SWR refreshes the content. You can disable by passingfalse
to this propertyrevalidateOnFocus
– set tofalse
to disable the focus-based refreshrefreshWhenHidden
andrefreshWhenOffline
for additional options for keeping the data fresh (these are disabled by default)
And many more. Interestingly, SWR will automatically retry when a network error occurs (5 seconds by default – errorRetryInterval
and you can set the maximum number of retries (errorRetryCount
).
See the options page for more details.
Wrap-up
Check out SWR on Vercel's site for more details, including special usages on Next.js, some really powerful paging features, injecting middleware, and more. I've prepared a simple demo app to play around with SWR at github.com/krimple/swr-demo.