-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Description
Bug report
When using the optimisticData
function (see #1850) does not use data from SSR fallback as currentData
.
As long as SWR has not revalidated the fallback data you can't really use it as basis for new optimisticData.
Description / Observed Behavior
consider this example
const myListResponse = useSWR(`api/myList`);
async function addToList(item) {
await myListResponse.mutate(
async () => { /* some fetch PATCH adding the item to the list */ },
{
populateCache: true,
rollbackOnError: true,
revalidate: false,
optimisticData(currentData?) {
return [...(currentData ?? []), item];
},
}
)
}
Even if fallback: { "api/myList": ["foo", "bar"] }
is set in <SWRConfig>
the currentData
argument is undefined
when addToList()
is called before the fallback has been revalidated.
This leads to undesired results:
data
is['foo', 'bar']
initially (from fallback)addToList('baz')
is calleddata
is now['baz']
(fromoptimisticData
function) becausecurrentData
wasundefined
but should have been['foo', 'bar']
- fetched data arrives
data
is now['foo', 'bar', 'baz']
In my case addToList
it is called from an effect but it could also be caused by a fast clicking user or slow network connection.
Expected Behavior
currentData
should use fallback
data if it can.
And the process should be like this:
data
is['foo', 'bar']
initially (from fallback)addToList('baz')
is calleddata
is now['foo', 'bar', 'baz']
(fromoptimisticData
function) becausecurrentData
was['foo', 'bar']
- fetched data arrives
data
still is['foo', 'bar', 'baz']
Repro Steps / Code Example
See snippet above - I'm not sure how to best create a repro without building a sample api. 🙈
Additional Context
SWR version.
2.0.0-beta.6
in next 12.2
I have found two possible workarounds.
- don't mutate if still loading:
async function addToList(item) {
if (myListResponse.isLoading) return;
await myListResponse.mutate(
…
- fallback to fallback data manually:
optimisticData(currentData?) {
currentData = currentData ?? myListResponse.data;
return [...(currentData ?? []), item];
},
Both seem suboptimal.
Thanks for investigating this. ❤️