Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mutate in useSWRInfinite is broken when passing data and revalidate true #908

Closed
pedro-pedrosa opened this issue Jan 18, 2021 · 12 comments · Fixed by #1301
Closed

mutate in useSWRInfinite is broken when passing data and revalidate true #908

pedro-pedrosa opened this issue Jan 18, 2021 · 12 comments · Fixed by #1301
Assignees

Comments

@pedro-pedrosa
Copy link

pedro-pedrosa commented Jan 18, 2021

Bug report

Description / Observed Behavior

When using useSWRInfinite, if we call the bound mutate function and we pass the data argument, the data is not updated or revalidated.

Expected Behavior

I expect useSWRInfinite to both update the cache and re-fetch data from source.

Repro Steps / Code Example

CodeSandbox

Notice how mutate(data) doesn't update the cache or revalidate the data but mutate(data, false) does update the cache. mutate() revalidates with no issues.

Additional Context

SWR version. 0.4.0

I guess this is because the mutate function for useSWRInfinite is not updating the cached pages with the data parameter before calling useSWR mutate. When the infinite fetcher adapter runs, this is equal: config.compare(originalData[i], pageData). mutate from useSWR will just update the global cache key for the infinite list, not the individual pages as this code would assume

@shuding shuding self-assigned this Jan 19, 2021
@pedro-pedrosa
Copy link
Author

forgot to save my sandbox before sharing. it should be okay now

@woxxy
Copy link

woxxy commented Feb 2, 2021

I can reproduce the above. A further issue: if you use useSWRInfinite with refreshInterval, you will lose any changes made every time the reload is run.

I found a workaround:

  • do the mutate() that is returned by useSWRInfinite as you would expect
  • use the import mutate() to modify the key-cache:
await importedMutate(
    getKey(pageIndex, paginatedData[pageIndex - 1]),
    (paginatedData) => { return modify(paginatedData) }
);

I take that this is updating the page cache forcefully and persist the change.

@filipeperdigaosousa
Copy link

@woxxy I have a similar issue.
I'm trying to mutate data using the mutate returned byuseSWRInfinitebut it doesn't revalidate.

Can you better explain your workaround?

When you mutate using getKeyare you mutating all the list or a single page?

I'm not understanding well how to mutate useSWRInfinite with filters and pages and other parameters.

Thanks in advance

@pedro-pedrosa
Copy link
Author

for workaround you can do:

mutate(data, false)
mutate()

the first one mutates the cache, the second triggers revalidation.

@simplenotezy
Copy link

@pedro-pedrosa That workaround does not work for me.

@simplenotezy
Copy link

@woxxy Could you elaborate more on your workaround, specifically regarding "use the import mutate() to modify the key-cache"? Perhaps with a code example, would be awesome!

@shuding
Copy link
Member

shuding commented Jul 19, 2021

If you want to revalidate all pages after mutating, you need to pass the revalidateAll: true option:

const { mutate } = useSWRInfinite(getKey, fetcher, { revalidateAll: true })

mutate(pages) // ← this will first mutate the local data, and then revalidate all pages

By default, SWR Infinite only revalidates the first page (there's a PR that fixes this behavior: #1301) that's because in most infinite loading cases, it's too expensive to revalidate everything.

@bryanltobing
Copy link

got connection refused every time i try to mutate data in swr infinite after updating the data / make a crud operation

@anonrig
Copy link

anonrig commented Nov 28, 2021

This bug fix somehow created a bug on Socketkit creating infinite loops using it with fallbackData.

Here's the issue: #1638 (comment)
Here's the code: https://github.com/socketkit/socketkit/blob/main/services/web/components/table/table.js#L37

@dwome
Copy link

dwome commented Jan 12, 2022

for workaround you can do:

mutate(data, false)
mutate()

the first one mutates the cache, the second triggers revalidation.

this is how I also got it working.
using the global mutate I changed the cache entry and with the mutate of the list I was able to trigger the revalidation.
Notice: you have to set revalidateFirstPage to true for the useSWRInfinite hook.

@shoaibhassan
Copy link

shoaibhassan commented Oct 23, 2022

for workaround you can do:

mutate(data, false)
mutate()

the first one mutates the cache, the second triggers revalidation.

After hours of back and forth hustle this way around works but it revalidate all the pages. revalidateAll: true will do the same I think.

@brunofin
Copy link

brunofin commented Jun 28, 2023

Not sure if anyone running on the same issue as me, but every google search I do on the subject leads me here, apparently using the bound mutate function from useSWRInfinite was not notifying my component tree that data has changed. My solution, as absurd as it seems, was to first mutate the collection to undefined before mutating it with my changed data before telling it to actually fetch fresh data. So in other words:

mutate(undefined, false);
mutate(mutatedData, false);
mutate();

It may be possible another undefined mutate be needed before the final mutate().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants