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

add helper function to clear deduping intervals #720

Closed
wants to merge 1 commit into from

Conversation

Arjun-sna
Copy link

The function added will help in clearing deduping interval before timeout set

Copy link
Member

@shuding shuding left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! Unfortunately I don't think it's a good idea to expose such an internal and low-level API. May I ask what's the exact use case?

@Arjun-sna
Copy link
Author

Thanks for the feedback. The use case is suppose I have a list of users fetched and render in a component using useSWR. And I have set dedupingInterval as 5mins for that fetch request. I can click on a user list item and see user details in separate component.

Now if I update the user in that component and come back to user list page, I will see the old data since new fetch won't happen before deduping interval timeout. I cannot use mutate as well since update is happening in a different component.

So in-order to trigger a new fetch, I needed a function to clear the dedupingInterval timeout already set for a key.

@pacocoursey
Copy link
Contributor

@Arjun-sna Could you use the global mutate function to forcefully revalidate when changing the user information?

https://swr.vercel.app/docs/mutation#revalidate

@Arjun-sna
Copy link
Author

@pacocoursey I tried using global mutate but that doesn't work if the component where we use useSWR to fetch the resource is unmounted. Basically mutate doesn't work if it is called in a component different from the component we fetched the resource using useSWR. Please correct me if I miss something here.

@Arjun-sna
Copy link
Author

Arjun-sna commented Oct 29, 2020

After looking into the code, I found that once the component where useSWR is unmounted, the onUpdate function is removed from CACHE_REVALIDATORS array. So we cannot use mutate to revalidate the same resource in other component.

@shuding
Copy link
Member

shuding commented Oct 29, 2020

Basically mutate doesn't work if it is called in a component different from the component we fetched the resource using useSWR

@Arjun-sna this is not true, did you test? Since SWR shares the cache globally, even if it’s another component, or it’s unmounted, calling mutate will update the cache and all places that are rendering the same resource will get updated.

@Arjun-sna
Copy link
Author

Arjun-sna commented Oct 29, 2020

@shuding You are right. The cache is global. But the mutate is not triggering a revalidation by making an API request again when called from component other the one which has the corresponding useSWR

When I tried to find the cause of that, I found that the trigger function has following line of code

const updaters = CACHE_REVALIDATORS[key]

Here CACHE_REVALIDATORS[key] will be an empty array once the component is unmounted because there is a clean up happening in useIsomorphicLayoutEffect inside useSWR

removeRevalidator(CACHE_REVALIDATORS, onUpdate)

Please find the codesandbox list to demo that https://codesandbox.io/s/swr-demo-5q3l1

@shuding
Copy link
Member

shuding commented Oct 30, 2020

@Arjun-sna yes, if all components using that resource are unmounted, mutate will do nothing. That's the expected behavior.

I think what you should do is this:

I cannot use mutate as well since update is happening in a different component.

You can use mutate by using the same resource inside the current component, like a "revalidate handler". For example:

function List () {
  const { data } = useSWR('/api/user')
  // render data...
}

function Button () {
  const { mutate } = useSWR('/api/user') // here we don't use the data, just use mutate
  return <button onClick={() => mutate()}>revalidate user</button>
}

So even if <List/> is unmounted, you can still revalidate the data of /api/user.

@Arjun-sna
Copy link
Author

@shuding Thanks for that workaround. The one issue with that approach though is it doesn't work for APIs with pagination related query params. Like if we want to invalidate a API with same url but different query params.

@Arjun-sna
Copy link
Author

Or will it be a better solution if removeRevalidator(CACHE_REVALIDATORS, onUpdate) is not done when component is unmounted. So that mutate will work from anywhere.

@lorenzomigliorero
Copy link

@shuding

You can use mutate by using the same resource inside the current component, like a "revalidate handler".

const { mutate } = useSWR('/api/user')

This row executes an unnecessary revalidation on Button mounting with the default fetcher implementation.

If we don't want to expose a clearDedupingInterval method, dedupingInterval should be cleared if mutate is called on an unmounted key.

I opened a similar issue yesterday.

@ivan-kleshnin
Copy link

ivan-kleshnin commented Jan 15, 2021

If my understanding of this PR is correct it's totally needed.

For example for SWR & NextJS combination the following code:

// Logout Handling
cache.clear()
Router.push("/some-url")

DOES NOT work for logout. Cached data is still there and affects rendering. This question was brought up previously btw.

The only way to fix logout seems to be a fallback to low-level window.location.href = "/some-url"
(a hack because it's a "hard" redirect involving server where client-only redirect could work just fine)

@smddzcy
Copy link

smddzcy commented Feb 8, 2021

This is still an issue. Global mutate function currently doesn't mutate the values if there's a dedupingInterval. Is there any workaround for this?

@osseonews
Copy link

Having the same issue. Global mutate function currently doesn't mutate the values if there's a deduping Interval and global mutate is called in a seperate component. I guess the only solution is to force a page refresh, to force a page re-render, which is not ideal.

@pacocoursey pacocoursey removed their request for review July 9, 2021 18:19
@Arjun-sna Arjun-sna closed this Aug 3, 2021
@ivan-kleshnin
Copy link

@osseonews the solution is to switch to React-Query (sorry SWR).

@rvirani1
Copy link

I love this library otherwise, but this is a super strange oversight with how the deduping interval is set. You basically can't log users out without forcing a page refresh. Am I missing something? I may actually have to consider react-query

@shuding shuding removed the request for review from Timer January 26, 2022 23:59
@shuding
Copy link
Member

shuding commented Jan 27, 2022

@rvirani1 on the latest version, mutate will invalidate the unmounted key so it should work fine now. The issue #828 was already fixed by #1498.

However if you’re still facing the issue, feel free to open a new issue and I’m happy to look into it.

@rvirani1
Copy link

rvirani1 commented Jan 27, 2022

@shuding Thanks for following up. If I'm logging a user out, can I clear the cache globally and get the same effect or do I have to call mutate on all known keys? If we have a Next.JS SPA, what's the recommended way to make sure no data leaks across users if someone logs out and logs in as someone else?

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 this pull request may close these issues.

8 participants