https://swr.vercel.app/blog/swr-v2 Skip to content SWR DocsExamplesBlog [ ] / GitHub [ ] / * Announcing SWR 2.0 * Announcing SWR 1.0 * Docs + Getting Started + API + Global Configuration + Data Fetching + Auto Revalidation + Arguments + Mutation & Revalidation + Error Handling + Conditional Data Fetching + Pagination + Prefetching + Next.js SSG and SSR + TypeScript + Suspense + Middleware + Advanced o Understanding SWR o Cache o Performance o React Native o Developer Tools + Change Log * Examples + Basic Usage + Authentication + Optimistic UI + Infinite Loading + Error Handling + Next.js SSR * Blog + Announcing SWR 2.0 o #Mutation and Optimistic UI o #SWR DevTools o #Preloading Data o #isLoading o #Preserving Previous State o #Extending Configurations o #Improved React 18 Support o #Migration Guide o #Changelog o #The Future & Thank You! + Announcing SWR 1.0 English light On This Page * Mutation and Optimistic UI * useSWRMutation * Optimistic UI * Mutate Multiple Keys * SWR DevTools * Preloading Data * isLoading * Preserving Previous State * Extending Configurations * Improved React 18 Support * Migration Guide * Fetcher No Longer Accepts Multiple Arguments * Global Mutate No Longer Accepts a getKey Function * New Required Property keys() for Cache Interface * Changed Cache Internal Structure * SWRConfig.default Is Renamed as SWRConfig.defaultValue * Type InfiniteFetcher Is Renamed as SWRInfiniteFetcher * Avoid Suspense on Server * ES2018 as the Build Target * Changelog * The Future & Thank You! Question? Give us feedback -Edit this page on GitHub - Blog Announcing SWR 2.0 Announcing SWR 2.0 December 9th, 2022 by Shu DingJiachi LiuToru KobayashiYixuan Xu Today, we are excited to announce the release of SWR 2.0! This new version comes with a lot of improvements and new features: new mutation APIs and improvements to optimistic UI scenarios, new DevTools, better support for concurrent rendering, etc. We would like to give a big shout-out to all the contributors and maintainers who helped make this release possible. Mutation and Optimistic UI# useSWRMutation# Mutation is an important part of the data-fetching process. They allow you to make changes to your data both locally and remotely. Our existing mutate API allows you to revalidate and mutate resources manually. In SWR 2.0, the new hook useSWRMutation makes it even simpler to remotely change data using a declarative API. You can set up a mutation using the hook, and then activate it later: 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 ( ) } The example above defines a sendRequest mutation that affects the '/ api/user' resource. Unlike useSWR, useSWRMutation will not immediately start the request upon rendering. Instead, it returns a trigger function that can later be called to manually start the mutation. The sendRequest function will be called when the button is clicked, with the extra argument { username: 'johndoe' }. The value of isMutating will be set to true until the mutation has finished. Additionally, this new hook addresses other issues you may have with mutations: * Optimistically update the UI while data is being mutated * Automatically revert when mutation fails * Avoid any potential race conditions between useSWR and other mutations of the same resource * Populate the useSWR cache after mutation completes * ... You can find in-depth API references and examples by reading the docs or scrolling through the next few sections. Optimistic UI# Optimistic UI is an excellent model for creating websites that feel fast and responsive; however, it can be difficult to implement correctly. SWR 2.0 has added some new powerful options to make it easier. Let's say we have an API that adds a new todo to the todo list and sends it to the server: await addNewTodo('New Item') In our UI, we use a useSWR hook to display the todo list, with an "Add New Item" button that triggers this request and asks SWR to re-fetch the data via mutate(): const { mutate, data } = useSWR('/api/todos') return <> However, the await addNewTodo(...) request could be very slow. When it's ongoing, users still see the old list even if we can already know what the new list will look like. With the new optimisticData option, we can show the new list optimistically, before the server responds: const { mutate, data } = useSWR('/api/todos') return <> SWR will immediately update the data with the optimisticData value, and then send the request to the server. Once the request finishes, SWR will revalidate the resource to ensure it's the latest. Like many APIs, if the addNewTodo(...) request returns us the latest data from the server, we can directly show that result, too (instead of starting a new revalidation)! There's the new populateCache option to tell SWR to update the local data with the mutate response: const { mutate, data } = useSWR('/api/todos') return <> At the same time, we don't need another revalidation afterward as the response data is from the source of truth, we can disable it with the revalidate option: const { mutate, data } = useSWR('/api/todos') return <> Lastly, if addNewTodo(...) fails with an exception, we can revert the optimistic data ([...data, 'New Item']) we just set, by setting rollbackOnError to true (which is also the default option). When that happens, SWR will roll back data to the previous value. const { mutate, data } = useSWR('/api/todos') return <> All these APIs are supported in the new useSWRMutation hook as well. To learn more about them, you can check out our docs. And here is a demo showing that behavior: Optimistic UI with automatic error rollback Mutate Multiple Keys# The global mutate API now accepts a filter function, where you can mutate or revalidate specific keys. This will be helpful for use cases such as invalidating all the cached data. To learn more, you can read Mutate Multiple Keys in the docs. import { mutate } from 'swr' // Or from the hook if you have customized your cache provider: // { mutate } = useSWRConfig() // Mutate single resource mutate(key) // Mutate multiple resources and clear the cache (set to undefined) mutate( key => typeof key === 'string' && key.startsWith('/api/item?id='), undefined, { revalidate: false } ) SWR DevTools# SWRDevTools is a browser extension that helps you debug your SWR cache and the fetch results. Check our devtools section for how to use devtools in your application. [cache-view] Preloading Data# Preloading data can improve the user experience tremendously. If you know the resource is going to be used later in the application, you can use the new preload API to start fetching it early: 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 } In this example, the preload API is called in the global scope. This means that we start to preload the resource before React even starts to render anything. And when the Profile component is being rendered, the data can probably be available already. If it's still ongoing, the useSWR hook will reuse that ongoing preloading request instead of starting a new one. The preload API can also be used in cases like preloading data for another page that will likely be rendered. More information about prefetching data with SWR can be found here. isLoading# isLoading is a new state returned by useSWR, that indicates if the request is still ongoing, and there is no data loaded yet. Previously, the isValidating state represents both the initial loading state and revalidating state so we had to check if both data and error are undefined to determine if it was the initial loading state. Now, it is so easy that you can directly use the isLoading value to render a loading message: import useSWR from 'swr' function Profile() { const { data, isLoading } = useSWR('/api/user', fetcher) if (isLoading) return
loading...
return
hello {data.name}!
} Note that isValidating is still present so you can still use it to show a loading indicator for revalidations. We have added the new Understanding SWR page to describe how SWR returns values, which includes the difference between isValidating and isLoading, and how to combine them to improve user experience. Preserving Previous State# The keepPreviousData option is a new addition that allows you to keep the data that was fetched before. This improves UX immensely when you're fetching data based on user actions happening in real time, like with a live search feature, where the resource's key keeps changing: function Search() { const [search, setSearch] = React.useState(''); const { data, isLoading } = useSWR(`/search?q=${search}`, fetcher, { keepPreviousData: true }) return (
setSearch(e.target.value)} placeholder="Search..." />
{data?.products.map(item => )
); } Keep previous search results when keepPreviousData has been enabled Check the code on CodeSandbox and you can read more about it here. Extending Configurations# SWRConfig can now accept a function value. When you have multiple levels of , the inner receives the parent configuration and returns a new one. This change makes it more flexible to configure SWR in a large codebase. More information can be found here . ({ dedupingInterval: parentConfig.dedupingInterval * 5, refreshInterval: 100, })} > Improved React 18 Support# SWR has updated its internal code to use useSyncExternalStore and startTransition APIs in React 18. These ensure stronger consistency when rendering UI concurrently. This change doesn't require any user code changes and all developers will benefit from it directly. Shims are included for React 17 and below. SWR 2.0 and all the new features are still compatible with React 16 and 17. Migration Guide# Fetcher No Longer Accepts Multiple Arguments# key is now passed as a single argument. - useSWR([1, 2, 3], (a, b, c) => { + useSWR([1, 2, 3], ([a, b, c]) => { assert(a === 1) assert(b === 2) assert(c === 3) }) Global Mutate No Longer Accepts a getKey Function# Now, if you pass a function to the global mutate, it will be used as a filter. Previously, you can pass a function that returns a key to the global mutate: - mutate(() => '/api/item') // a function to return a key + mutate('/api/item') // to mutate the key, directly pass it New Required Property keys() for Cache Interface# When you use your own cache implementation, the Cache interface now requires a keys() method that returns all keys in the cache object, similar to the JavaScript Map instances. interface Cache { get(key: string): Data | undefined set(key: string, value: Data): void delete(key: string): void + keys(): IterableIterator } Changed Cache Internal Structure# The internal structure of the cache data will be an object that holds all the current states. - assert(cache.get(key) === data) + assert(cache.get(key) === { data, error, isValidating }) // getter - cache.get(key) + cache.get(key)?.data // setter - cache.set(key, data) + cache.set(key, { ...cache.get(key), data }) You should not write to the cache directly, it might cause undefined behavior. SWRConfig.default Is Renamed as SWRConfig.defaultValue# SWRConfig.defaultValue is the property for accessing the default SWR config. - SWRConfig.default + SWRConfig.defaultValue Type InfiniteFetcher Is Renamed as SWRInfiniteFetcher# - import type { InfiniteFetcher } from 'swr/infinite' + import type { SWRInfiniteFetcher } from 'swr/infinite' Avoid Suspense on Server# If you want to use suspense: true with SWR on the server-side, including pre-rendering in Next.js, then you must provide initial data via fallbackData or fallback. Today, this means that you can't use Suspense to fetch data on the server side. Your other two options are doing fully client-side data-fetching or getting your framework to fetch the data for you (like getStaticProps does in Next.js). ES2018 as the Build Target# If you want to support IE 11, you have to target ES5 in your framework or a bundler. This change has made a performance improvement on SSR, and keeps the bundle size small. Changelog# Read the full Changelog on GitHub. The Future & Thank You!# With the new release of Next.js 13, we see a lot of exciting new things as well as paradigm shifts in the React ecosystem: React Server Components, streaming SSR, async components, and the use hook. Many of them are related to data-fetching, and some of them have overlapping use cases with SWR. However, the goal of the SWR project remains the same. We want it to be a drop-in library that is lightweight, framework agnostic, and a little bit opinionated (i.e. revalidate upon focus). Instead of trying to be a standard solution, we want to focus on innovations that make the UX better. In the meantime, we are also doing research on how to improve SWR with these new abilities of React. We want to thank every one of the 143 contributors (+ 106 docs contributors), as well as those who helps us out or gave feedback. A special thanks goes to Toru Kobayashi for all his work on DevTools and docs- we couldn't have done it without you! Last updated on December 9, 2022 Announcing SWR 1.0 English light Powered by