swr icon indicating copy to clipboard operation
swr copied to clipboard

infinite: do not revalidate every page on mutate(undefined)

Open hazae41 opened this issue 3 years ago • 11 comments

Bug report

Description / Observed Behavior

When I use .mutate(), all pages are revalidated even tough nothing changed in the first page, and the keys didn't change

This behaviour happens regardless of revalidateIfStale, and regardless of the new revalidateFirstPage

Expected Behavior

Do not revalidate if the first page is the same and keys are the same

Repro Steps / Code Example

const key = useCallback((page: number, previous: Data | null) => {
  // First page
  if (page === 0 || !previous)
    return h(`topics`) // h is just a query builder
  // No next page
  if (!previous.after)
    return null
  // Next page
  const [after] = previous.after
  return h(`topics`, { after })
}, [])

const res = useSWRInfinite<Data>(key, fetcher, {})

const refresh = useCallback(() => {
  res.mutate()
}, [res])

return <button onClick={refresh}>
  refresh
</button>

Additional Context

happening on both [email protected] and [email protected]

hazae41 avatar Oct 25 '21 15:10 hazae41

This also happens on automatic revalidation

hazae41 avatar Oct 27 '21 18:10 hazae41

Ok, this comes to the fact that mutate() becomes mutate(undefined)

Fix is:

const refresh = useCallback(() => {
  res.mutate(d => d, true)
}, [res.mutate])

hazae41 avatar Oct 27 '21 20:10 hazae41

Still happens on beta 8, all pages are revalidated when doing mutate(undefined)

const refresh = useCallback(() => {
  res.mutate(d => d, true)
}, [res.mutate])

hazae41 avatar Nov 05 '21 18:11 hazae41

Very weird, let me try to reproduce this.

shuding avatar Dec 01 '21 15:12 shuding

If you call res.mutate(), everything will be revalidated. That's currently the expected behavior:

https://github.com/vercel/swr/blob/e1677522d86017ec84099f90be03ec9607baf34b/infinite/index.ts#L190-L191

We need to improve the local mutation API for pages a bit.

shuding avatar Dec 23 '21 17:12 shuding

Hi!

Have there been any updates regarding this issue? I'd like to be able to mutate & revalidate a specified page, and not all the loaded pages when calling mutate(). Is this possible in any way with the current implementation?

iDarkLightning avatar Jan 29 '22 07:01 iDarkLightning

Hi! Any updates regarding this issue?

misa-minic avatar Jun 02 '23 07:06 misa-minic

If you find this annoying, you can use my library

https://github.com/hazae41/xswr

You can revalidate any single page without revalidating everything

hazae41 avatar Jun 20 '23 18:06 hazae41

I have to use SWR only, but I found some work around. Thanks!

misa-minic avatar Jun 22 '23 10:06 misa-minic

hi @misa-minic could you share your solution? I thought about storing all items into a useState and then modifying a specific item after it's updated but I feel there should be a better solution

khanhld1910 avatar Aug 14 '23 07:08 khanhld1910

Hi @khanhld1910 Sorry for the late reply, I hope you found the solution by now.

If not, take a look at: https://swr.vercel.app/docs/mutation.en-US#mutate-multiple-items

You should be able with mutate to update only a certain KEY which represents each api call/url for getting a next "page" of items. In my case, I find the index of the item I updated e.g. index 15, then I could say, refetch only 10 items, from index 10 to index 20. This way I am not updating all the fetched items, but only 10 among which is my updated item.

Let me know if you need some info.

misa-minic avatar Sep 05 '23 09:09 misa-minic