Hey everyone, Vercel recently released version 2.0 of their data fetching hooks, known as useSWR
. This is a significant update that comes with several new features and improvements.
If you don't know Vercel or Next.js I recommend you to give a look here.
useSWRMutation hook
At its core, useSWR
is a hook for fetching data in React, much like the powerfull React Query that I love so much. It now includes a useSWRMutation
hook that allows you to send requests by first passing in a key and then the request function. The hook returns a trigger
function and a isMutating
boolean indicating whether it is mutating or not.
Here some examples from their documentation:
javascript
import useSWRMutation from 'swr/mutation';
async function sendRequest(url, { arg }) {
return fetch(url, {
method: 'POST',
body: JSON.stringify(arg),
});
}
function App() {
const { trigger, isMutating } = useSWRMutation('/api/user', sendRequest);
return (
<button disabled={isMutating} onClick={() => trigger({ username: 'johndoe' })}>
{isMutating ? 'Creating...' : 'Create User'}
</button>
);
}
Optimistic updates
One of the main use cases for this hook is optimistic UI. When you update data on a distant server with low latency, it can take some time for the update to reflect in the UI. To address this, you can use an optimistic update, which updates the data on the frontend before getting confirmation from the server.
For example, if you're fetching a list of any data from an API, you can use the mutate function after adding a new item to refresh the data and pass in optimistic data. If the mutation is successful, you can set populateCache
to true
and revalidate
to false
, making the optimistic data the new source of truth.
javascript
const { mutate, data } = useSWR('/api/todos');
return (
<>
<ul>{/* Display data */}</ul>
<button
onClick={() => {
mutate(addNewTodo('New Item'), {
optimisticData: [...data, 'New Item'],
populateCache: true,
});
}}
>
Add New Item
</button>
</>
);
Rolling back
In case the mutation fails, you can use the rollbackOnError
option, which is enabled by default, to roll back the optimistic update.
Preloading data
In addition to the mutation hook, useSWR
also includes a preload
function that lets you load data as soon as the JavaScript module is in scope. This means you can start preloading the data before React even begins to render anything! If you've already preloaded the data, useSWR
will fall back to it and avoid duplicating the preloading process.
javascript
import useSWR, { preload } from 'swr';
const fetcher = (url) => fetch(url).then((res) => res.json());
// You can call the preload function in anywhere
preload('/api/user', fetcher);
function Profile() {
// The component that actually uses the data:
const { data, error } = useSWR('/api/user', fetcher);
// ...
}
export function Page() {
return <Profile />;
}
isLoading and isValidating states
The hook also includes a new state, isLoading
, which only triggers when the data is being fetched for the first time, as opposed to isValidating
which triggers every time the data is revalidated.
keepPreviousData feature
And finally, last but not least, the feature keepPreviousData
, it lets you hold onto data even after it's been fetched, enhancing the user experience in real-time situations, like with live search. This is especially handy when the search resource's key is constantly changing.
javascript
function Search() {
const [search, setSearch] = React.useState('');
const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, {
keepPreviousData: true,
});
return (
<div>
<input type="text" value={search} onChange={(e) => setSearch(e.target.value)} placeholder="Search..." />
<div className={isLoading ? 'loading' : ''}>
{data?.products.map((item) => (
<Product key={item.id} name={item.name} />
))}
</div>
</div>
);
}
Overall, I think useSWR hook is a fantastic addition to the React data fetching ecosystem. And now, are you thinking to start using it?