Releases: vercel/swr
2.0.0-beta.0
SWR 2.0 coming soon, and this is the first beta version!
Keep in mind that APIs might still change until the stable release. Documentation will also be updated once stable.
💖 Give feedback in discussion: #1919.
Highlights
useSWRMutation — dedicated API for remote mutations, e.g. POST (#1450)
Added in #1450, the new useSWRMutation
hook covers all the use cases of:
- Requests that change data on the remote side: such as POST, PUT, DELETE, etc.
- Requests that need to be triggered manually, instead of automatically by SWR.
- Passing extra argument to fetcher, when triggering a request.
- Knowing the status of a mutation, similar to
isValidating
but for mutations. - A lot more...
Here's a quick example of how it looks:
import useSWRMutation from 'swr/mutation'
async function sendRequest(url, { arg }) {
return fetch(url, {
method: 'POST',
body: JSON.stringify(arg)
})
}
function App() {
const { trigger } = useSWRMutation('/api/user', sendRequest)
return <button onClick={() => {
trigger({ username: 'johndoe' })
}}>Create User</button>
}
In this example, the "fetcher", which is sendRequest
, will receive the value { username: 'johndoe' }
as the arg
from the second parameter. The request will only be triggered when clicking the button.
The new useSWRMutation
hook is actually more powerful than this, it also supports:
- Optimistic updates
- Automatic error rollback
- Detect and avoid race conditions between
useSWR
- Populate the cache of
useSWR
after mutation finishes - ...
More examples to come.
Breakings
Fetcher no longer accepts multiple arguments (#1864)
Previously, if the key
is an array, the values will be passed to the fetcher
function as arguments separately. In 2.0, the key
will always be passed to the fetcher
as is.
Before:
// SWR 1.x
useSWR([1, 2, 3], (a, b, c) => {
assert(a === 1)
assert(b === 2)
assert(c === 3)
})
After 2.0.0:
// SWR 2.0.0
useSWR([1, 2, 3], (a) => {
assert(a === [1, 2, 3])
})
Internal structure of the cached data (#1863)
This change affects the code that directly reads/writes to the cache, or provides a cache preset. For example if you have something like cache.set(key, value)
, you'll have to update your code.
Previously, the cached value of key
will be the associated data
, so this was guaranteed:
// SWR 1.x
assert(cache.get(key) === data)
And we keep other states (error
, isValidating
) with a special, prefixed key. Something like '$err$' + key
.
Since 2.0.0, the internal structure will be an object that holds all the current states:
// SWR 2.0.0
assert(cache.get(key) === { data, error, isValidating })
So you will have to do the following change to your code, get
:
- cache.get(key)
+ cache.get(key)?.data
And set
:
- cache.set(key, data)
+ cache.set(key, { ...cache.get(key), data })
What's Changed
- bugfix: make suspense and revalidateIfStale work together by @simowe in #1851
- feat: support functional optimisticData by @huozhi in #1861
- test: fix an act warning by @koba04 in #1888
- breaking: Change the fetcher argument to be consistent with the passed key by @shuding in #1864
- Keep all fields with one single key by @shuding in #1863
- fix: wrong spell by @baojie223 in #1902
- Update React 18 dependencies by @shuding in #1824
- build(deps): bump minimist from 1.2.5 to 1.2.6 by @dependabot in #1903
- type: make type inference simpler by @promer94 in #1908
- type: fix type error on SWRConfig by @himself65 in #1913
- feat: Hook for remote mutations by @shuding in #1450
New Contributors
- @simowe made their first contribution in #1851
- @baojie223 made their first contribution in #1902
- @himself65 made their first contribution in #1913
Full Changelog: 1.2.2...2.0.0-beta.0
1.3.0
What's Changed
- type: fix type error on SWRConfig by @himself65 in #1913
- chore: update React 18 dependencies by @shuding in #1824
- test: fix an act warning by @koba04 in #1888
- feat: support functional optimisticData by @huozhi in #1861
- bugfix: make suspense and revalidateIfStale work together by @simowe in #1851
Full Changelog: 1.2.2...1.3.0
1.2.2
Highlights of This Release
populateCache
Option Now Supports Function
We added better Optimistic UI support in v1.2.0. However, what if your API is only returning a subset of the data (such as the mutated part), that can be populated into the cache? Usually, an extra revalidation after that mutation is needed. But now you can also use a function as populateCache
to transform the mutate result into the full data:
await mutate(addTodo(newTodo), {
optimisticData: [...data, newTodo],
rollbackOnError: true,
populateCache: (addedTodo, currentData) => {
// `addedTodo` is what the API returns. It's not
// returning a list of all current todos but only
// the new added one.
// In this case, we can transform the mutate result
// together with current data, into the new data
// that can be updated.
return [...currentData, addedTodo];
},
// Since the API already gives us the updated information,
// we don't need to revalidate here.
revalidate: false,
});
The new definition:
populateCache?: boolean | ((mutationResult: any, currentData: Data) => Data)
Here is a demo for it: https://codesandbox.io/s/swr-basic-forked-hi9svh
Bug Fixes
What's Changed
- refactor: revalidateIfStale has an effect on updates, not only mounting by @koba04 in #1837
- fix: reset stale unmountedRef in suspense by @promer94 in #1843
- test: add a test for the behavior of revalidateOnMount when the key has been changed by @koba04 in #1847
- feat: Support
populateCache
as a function by @shuding in #1818
Full Changelog: 1.2.1...1.2.2
1.2.1
Highlights of This Release
shouldRetryOnError
accepts a function
Previously shouldRetryOnError
is either true or false. Now it accepts a function that conditionally determines if SWR should retry. Here's a simple example:
const fetcher = url => fetch(url).then(res => {
// Fetcher throws if the response code is not 2xx.
if (!res.ok) throw res
return res.json()
})
useSWR(key, fetcher, {
shouldRetryOnError: (error) => {
// We skip retrying if the API is returning 404:
if (error.status === 404) return false
return true
}
})
Thanks to @sairajchouhan for contributing!
What's Changed
shouldRetryOnError
accepts a function that can be used to conditionally stop retrying by @sairajchouhan in #1816- build(deps-dev): bump next from 12.0.8 to 12.0.9 by @dependabot in #1821
- fix: useSWRInfinite revalidates with revalidateOnMount by @koba04 in #1830
New Contributors
- @sairajchouhan made their first contribution in #1816
Full Changelog: 1.2.0...1.2.1
1.2.0
Highlights of This Release
Optimistic Updates with Auto Error Rollback
There are now some new options in mutate
:
mutate(patchUser(user), {
optimisticData: user,
populateCache: true,
rollbackOnError: true,
revalidate: true,
})
Here the cache will be immediately updated to user
, the “optimistic value”. And then a request (remote mutation) is started via patchUser(user)
and the response will be written to the cache. If that request fails, the original result will be rolled back safely so the optimistic value will be gone. And after all those finish, a revalidation will start to fetch the latest value.
This is extremely helpful for building the optimistic UI pattern.
You can do the same for the global mutate
, just remember to pass the key. Also, the current mutate
APIs stay unchanged so mutate(data, false)
works the same.
Here's an example: https://codesandbox.io/s/swr-basic-forked-k5hps.
CleanShot.2022-01-27.at.15.39.58.mp4
.mjs
Support
SWR now has .mjs
exported for bundlers that prefer this format.
This doesn’t break environments that don’t support .mjs
. An alternative .esm.js
and CJS bundle are also published.
You can read more about ES modules here.
What's Changed
- feat: Optimistic mutation with error rollback by @shuding in #1745
- fix: Required return type when mutating by @RKatarine in #1772
- fix: use the latest reference of fetcher with suspense mode by @koba04 in #1803
- test: add delay for flaky focus test by @huozhi in #1762
- test: remove flaky focus test case by @huozhi in #1793
- test: use @swc/jest by @huozhi in #1790
- chore: Ignore coverage report by @shuding in #1744
- chore: Merge mutation states by @shuding in #1748
- chore: Rename CONCURRENT_REQUESTS to FETCH by @shuding in #1749
- chore: Merge extra request states in cache by @shuding in #1752
- chore: support mjs exports by @huozhi in #1760
- chore: remove useless react-native field by @huozhi in #1761
- chore: comment helper by @huozhi in #1757
- chore: display name in devtool by @huozhi in #1779
- chore: simplify example development by @huozhi in #1787
- chore: build: improve watch commands by @huozhi in #1788
- chore: Update examples and dependencies by @shuding in #1789
- chore: zeit -> vercel by @huozhi in #1791
- chore: Clean up configurations by @shuding in #1792
- chore: move community health files to .github dir by @huozhi in #1794
- chore: Add link to security email directly by @huozhi in #1795
New Contributors
- @RKatarine made their first contribution in #1772
Full Changelog: 1.1.2...1.2.0
1.2.0-beta.1
What's Changed
- doc: comment helper by @huozhi in #1757
- build: support mjs exports by @huozhi in #1760
- chore: remove useless react-native field by @huozhi in #1761
- test: add delay for flaky focus test by @huozhi in #1762
- Required return type when mutating by @RKatarine in #1772
- polish: display name in devtool by @huozhi in #1779
New Contributors
- @RKatarine made their first contribution in #1772
Full Changelog: 1.1.2...1.2.0-beta.1
1.2.0-beta.0
Highlights of This Release
Dedicated API for Optimistic Updates with Auto Rollback on Error
There are now some new options in mutate
:
mutate(patchUser(user), {
optimisticData: user,
populateCache: true,
rollbackOnError: true,
revalidate: true,
})
Here the cache will be immediately updated to user
, the “optimistic value”. And then a request (remote mutation) is started via patchUser(user)
and the response will be written to the cache. If that request fails, the original result will be rolled back safely so the optimistic value will be gone. And after all those finish, a revalidation will start to fetch the latest value.
This is extremely helpful for building the optimistic UI pattern.
You can do the same for the global mutate
, just remember to pass the key. Also, the current mutate
APIs stay unchanged so mutate(data, false)
works the same.
Here's an example: https://codesandbox.io/s/swr-basic-forked-k5hps.
What's Changed
- feat: Optimistic mutation with error rollback by @shuding in #1745
- chore: Ignore coverage report by @shuding in #1744
- chore: Merge mutation states by @shuding in #1748
- chore: Rename CONCURRENT_REQUESTS to FETCH by @shuding in #1749
- Merge extra request states in cache by @shuding in #1752
Full Changelog: 1.1.2...1.2.0-beta.0
1.1.2
Highlights of This Release
Use the Latest Fetcher Function
SWR will now use the latest fetcher function passed to the hook, when sending the request. Previously it uses the initial snapshotted fetcher.
Avoid Unnecessary Auto Revalidations
When refocusing on the window with state changes (like clicking a button that changes the SWR key immediately), SWR now avoids revalidations if they're not necessary. Details can be found in #1720.
New Types for useSWRInfinite
Two types for useSWRInfinite
are added: SWRInfinteHook
and SWRInfinteKeyLoader
. You can use them to type the hook and the getKey
function.
New populateCache
option for mutate
A new option to control if the mutation data should be written to the cache. You can find the details in #1729.
What's Changed
- Make polyfill for
requestAnimationFrame
more robust by @thomaspaulmann in #1707 - type(infinite): export SWRInfinteHook and SWRInfiniteKeyLoader from infinite, rename InfiniteFetcher to SWRInfiniteFetcher by @houkanshan in #1714
- feat: Ensure auto revalidations are executed after state updates by @shuding in #1720
- Add moduleNameMapper to jest by @shuding in #1724
- Improve test by @promer94 in #1725
- feat: Use the latest reference of fetcher by @shuding in #1727
- fix: Re-export InfiniteFetcher by @shuding in #1728
- feat: Add
populateCache
option tomutate
by @shuding in #1729 - Fix local state sharing example deps by @huozhi in #1737
- Merge states for concurrent requests by @shuding in #1741
- Skip error retrying when document is not active and improve tests by @shuding in #1742
New Contributors
- @thomaspaulmann made their first contribution in #1707
- @houkanshan made their first contribution in #1714
Full Changelog: 1.1.1...1.1.2
1.1.2-beta.1
Highlights of This Release
1. More Tests and Better Code Coverage
We now have 23 test suits of 202 total test cases, with a 98.06% test coverage. The core files and main functionalities are now 100% covered. Kudos to @promer94 for improving it!
2. Use the Latest Fetcher Function
SWR will now use the latest fetcher function passed to the hook, when sending the request. Previously it uses the initial snapshotted fetcher.
3. Avoid Unnecessary Auto Revalidations
When refocusing on the window with state changes (like clicking a button that changes the SWR key immediately), SWR now avoids revalidations if they're not necessary. Details can be found in #1720.
4. New Types for useSWRInfinite
Two types for useSWRInfinite
are added: SWRInfinteHook
and SWRInfinteKeyLoader
. You can use them to type the hook and the getKey
function.
What's Changed
- type(infinite): export SWRInfinteHook and InfiniteKeyLoader from infinite by @houkanshan in #1714
- feat: Ensure auto revalidations are executed after state updates by @shuding in #1720
- Add moduleNameMapper to jest by @shuding in #1724
- Improve test by @promer94 in #1725
- feat: Use the latest reference of fetcher by @shuding in #1727
New Contributors
- @houkanshan made their first contribution in #1714
Full Changelog: 1.1.2-beta.0...1.1.2-beta.1
1.1.2-beta.0
What's Changed
- Make polyfill for
requestAnimationFrame
more robust by @thomaspaulmann in #1707
New Contributors
- @thomaspaulmann made their first contribution in #1707
Full Changelog: 1.1.1...1.1.2-beta.0