SWR is a fast, lightweight, and reusable data fetching library from the good folks at Vercel that I use in my Next.js apps! SWR stands for stale-while-revalidate; if you're not familiar with that concept, here's a bit of background:
A cached response is stale when it exceeds the
max_age
specified in itsCache-Control
header. When a request is made and the response is fresh (newer than themax_age
), the cached data is returned. However, if the cached response is stale β a revalidation of the response occurs which then caches the new response for future use.
Data Fetching
In its simplest form, this is how you use SWR:
const { data, error } = useSWR('/api/user', fetcher)
What I like about SWR is that data is tied to a key (usually an endpoint), so whenever you need that data, instead of hitting the endpoint again, you get the cached data from SWR. Oftentimes, I create a custom hook and call that hook in different places within my app so everything stays consistent.
For instance, when I update my avatar on the profile page, it instantly gets updated in the sidebar because both components are pulling from the same resource!
Why is this a good thing? Take this screenshot of an example app below. There are 3 components (<Sidebar />
, <UpdateProfile />
, and <Groups />
) that use the code snippet above to get the signed-in user's data. The beauty of this is that since the data is tied to a key, only one request will be sent! SWR dedupes*, caches, and shares the data across all instances; in this case, all components receive the data from the response.
Optimistic UI
Let's keep the "updating your profile" scenario, it's relatable! Say you're updating your avatar and you press save and it immediately updates! You might say wow, that was super fast! More times than not, that's optimistic UI. What's happening behind the scenes is the new data is being sent to the UI immediately while the request happens in the background. If there's an error with the request, the new data is removed and the UI goes back to its original state. This makes your app feel smooth and snappy which greatly impacts your users' overall experience!
Notice how on the left, showing a loading state temporarily pauses the user from interacting with our app. This delay can get longer depending on the user's network connection. On the right, however, the user can get back to using our app immediately and if something goes wrong with the request, the data seamlessly rolls back to its original state β¨
You can achieve optimistic UI with SWR pretty easily. When mutating, three things happen:
-
the query's cache is immediately updated with the new data
-
a request to the server is fired in the background (to perform the mutation)
-
the query is then revalidated
Remember how I told you that data is tied to a key? When a query's cache is modified, the data is broadcasted to all instances of that query so you don't have to revalidate each instance separately. This makes for real-time updates across your app, making the experience that much more delightful! I was chatting with Shu Ding, core maintainer of SWR, about some interesting behavior I encountered and it led to this recommended implementation of optimistic UI.
mutate(updateUser(data), {
optimisticData: data,
populateCache: true,
revalidate: true,
rollbackOnError: true,
});
It's pretty clear to see the fine-grained control you have over such a critical piece of the user's experience!
Some Cool Nuggets
-
SWR allows for different revalidation methods β queries automatically revalidate when refocusing on the window but you can also revalidate after a certain amount of time or even when you reconnect to the internet β¨
-
You can use GraphQL with SWR π Just update the
fetcher
to use a library likegraphql-request
orurql
-
Take advantage of React 18's Suspense mode in SWR by adding
{ suspense: true }
to an individual query our target all queries by adding it to the global config (<SWRConfig />)
at the root of your project. -
You can also use regular expressions to mutate multiple keys. Check out the custom hook π
* dedupe: a technique for removing duplicate/repeating data
β€οΈ Open Source Software