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

Reloading initialData after mutation #451

Closed
nfantone opened this issue Jun 10, 2020 · 7 comments
Closed

Reloading initialData after mutation #451

nfantone opened this issue Jun 10, 2020 · 7 comments

Comments

@nfantone
Copy link

nfantone commented Jun 10, 2020

I'm having some trouble understanding the proper pattern when trying to update/revalidate data from one view/page that's being mutated somewhere else. I'm using swr in a Next.js project.

The scenario I'm facing is a fairly basic one:

  • /users: A main page with a list of users. Fetches data using a /api/users key.
  • /users/[username]: A details page where you can edit attributes of a single user. Fetches data using a /api/users/[username] key.

If you edit a user, changes to its attributes should be reflected back on the list when going back - which it did, until I introduced SSR via initialData.

/users page has a getServerSideProps fetching all users on the list. Those are plugged into useSWR as { initialData }. This effectively avoids having to fetch users client side on first render, but makes it so it doesn't refresh the list after editing a user entry: it always returns the original initialData value.

Things I've tried:

  1. Adding revalidateOnMount: true to the useSWR call. This solves the problem, but entirely defeats the purpose of passing initialData in as the exact same set of users is unnecessarily fetched twice: once SS from getServerSideProps, once CS from the hook.

  2. Calling mutate('/api/users') from the edit page after successfully submitting the edit form. This would look like the natural solution to my issue. According to the docs, it should "broadcast a revalidation message globally to all SWRs with the same key" - but in my case, I found it doesn't seem to do anything at all.

  3. Same as above, but calling mutate('/api/users', async users => ...). However, the users array from the callback is always undefined for me. I would have expected the last set of fetched users from the list to be passed. Does this work when navigating between SSR'd pages?

  4. Same as above, but explicitly passing a new list of users with mutate('/api/users', fetch('/api/users')). This works fine, but suffers from the same double fetching quirk as 1. Not to mention the incursion of a clear violation of SoC patterns.

So what's the expected way to go about this? initialData changes after a mutation and the server returns the correct value. However, it seems as though, swr ignores new data after being set the first around and doesn't "reload" or "reinitialize" it. While this might be intentional (mimic'ing things like useState), how do I refresh my stale data without fetching the same more than once?

@sergiodxa
Copy link
Contributor

You can try deleting the cached key of the list of users after you update the user

import { cache } from "swr"

cache.delete("/api/users")

Then when you go back to the list, since there is no data currently cached it should use the initialData you provided.

@nfantone
Copy link
Author

@sergiodxa Wow, worked like a charm. Thanks so much! Is this API documented somewhere?

@huozhi
Copy link
Member

huozhi commented Jun 11, 2020

@nfantone it's not fully documented on readme yet, but you can take a look on the file https://github.com/vercel/swr/blob/master/src/cache.ts
hope this is helpful for you

@nfantone
Copy link
Author

@huozhi Awesome. Thanks for sharing!

In the same tenor, I'm still wondering why, if clearing the cache works, the other solutions didn't cut it for me. The more I learn about this, the more inclined I am to say this is really a bug.

Shouldn't mutate('/api/users') have worked as per its doc's description? Why was the array of users undefined on the mutate callback?

@hutber
Copy link

hutber commented Aug 24, 2020

I completely agree with @nfantone I am struggling to get my head round how to update the cache and when to after mutating data. :)

@ssorallen
Copy link

@nfantone RE: 2. in your list, the issue seems to be documented in #751

If you call mutate on a key when there are no mounted components with a useSWR for that key, then mutate is effectively a no-op. I ran into this and ended up manually clearing the cache for that specific key as well. There is no fetcher to go do the re-validation when a mutate is called in that case, but maybe it should be an option to do this cache clearing if there are no fetchers.

@shuding
Copy link
Member

shuding commented Dec 24, 2021

Same as #751, this issue should have been fixed with #1498: the existing cache will be invalidated with mutate and fallbackData will be used again.

@shuding shuding closed this as completed Dec 24, 2021
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

No branches or pull requests

6 participants