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

Passing an updated fetcher method has no effect #1131

Closed
PMudra opened this issue Apr 20, 2021 · 7 comments
Closed

Passing an updated fetcher method has no effect #1131

PMudra opened this issue Apr 20, 2021 · 7 comments
Labels
good first issue Good for newcomers

Comments

@PMudra
Copy link

PMudra commented Apr 20, 2021

Bug report

Description / Observed Behavior

Passing an updated fetcher method to useSWR has no effect. The initial version of the fetcher will be used.

I am passing a fetcher function to useSWR that is updated by applying a new access token.

const [accessToken, setAccessToken] = useState("valid-0");
const fetcher = () => {
  console.log("fetch with token:", accessToken);
};
const swrWithOutdatedFetcher = useSWR("key", fetcher);

When I call setAccessToken("valid-1") at some point (and revalidate), the output will still be "fetch with token: valid-0".

Expected Behavior

I was expecting swr to use the updated fetcher method. I believe this is the expected way when working with hooks in react.

In my example I'd expect "fetch with token: valid-1".

The workaround for now is to use useRef in combination with useEffect and then call fetcherRef.currect().

const fetcherRef = useRef(fetcher);
useEffect(() => {
  fetcherRef.current = fetcher;
});
const swrWithUpdatedFetcher = useSWR("key", () => fetcherRef.current());

If this behavior is intended, some words about this is the docs would be helpful and appreciated.

Repro Steps / Code Example

A simple example to reproduce and also the workaround using useRef:

https://codesandbox.io/s/autumn-butterfly-c4xe2?file=/src/App.tsx

Additional Context

SWR version 0.5.5

Related: #515 #927

swr/src/use-swr.ts

Lines 479 to 486 in 3d380e2

// FIXME:
// `fn` and `config` might be changed during the lifecycle,
// but they might be changed every render like this.
// `useSWR('key', () => fetch('/api/'), { suspense: true })`
// So we omit the values from the deps array
// even though it might cause unexpected behaviors.
// eslint-disable-next-line react-hooks/exhaustive-deps
[key]

@shuding shuding added the documentation Improvements or additions to documentation label May 4, 2021
@shuding
Copy link
Member

shuding commented May 4, 2021

Changing fetcher during render might cause unexpected behavior, so it will be ignored and won't trigger a refetch. This is simply because people can pass e.g. anonymous function as the fetcher that will be re-declared on every render. In SWR, key is always the identifier of the resource.

@PMudra
Copy link
Author

PMudra commented May 7, 2021

I agree that a changed fetcher should not trigger a refetch. What I expected is that the next refetch uses the latest fetcher I have passed to the hook.

Passing the token as a key to the hook looks promising at first thought. But that would lead to an immediate refetch of all resources which I do not want. The data hasn't changed. Just the way to get it (the next time I need it).

@Gyllsdorff
Copy link

Gyllsdorff commented May 9, 2021

Changing fetcher during render might cause unexpected behavior, so it will be ignored and won't trigger a refetch.

I agree that a changed fetcher should not trigger a refetch. What I expected is that the next refetch uses the latest fetcher I have passed to the hook.

➕1 on that. FWIW; I know several developers that didn't understand that the fetcher instance that was first used as the fetcher for that set of keys (and component?) will be used for all/most subsequent request (for that set of keys).

Is it possible to add some information about this to the Data fetching page? It feels like 99% of the time when we pass a fetcher directly to useSWR we do it the wrong way, it is likely better to configure the fetch using the global configuration.

@ivan-kleshnin
Copy link

ivan-kleshnin commented May 21, 2021

It feels like 99% of the time when we pass a fetcher directly to useSWR we do it the wrong way, it is likely better to configure the fetch using the global configuration.

This can't be true. We use local fetchers most of the time and something like this is very common in our code:

export const useFetchJobTalents = (
  params : FetchJobTalentsParams, query : FetchJobTalentsQuery, options
) : SWRResponse<FetchJobTalentsResult> => {
  options = ... // omitted for brevity

  const cacheKey = [fetchJobTalents.url, params.jobId, stringify(query)]
  useSWR_GarbageCollection(cacheKey)

  return useSWR(cacheKey, () => {
    return fetchJobTalents(params, query) // custom fetcher
  }, options)
}

@zlace0x
Copy link

zlace0x commented Nov 30, 2021

Also faced this as an issue, this is not a given reading the docs.

@0xMAJIMAK
Copy link

Have also faced this issue, given the nature of hooks it would be assumed that if new instances of the fetcher would be used when the key changes.

@shuding shuding added good first issue Good for newcomers and removed documentation Improvements or additions to documentation labels Nov 30, 2021
@shuding
Copy link
Member

shuding commented Nov 30, 2021

Would love to accept a PR to improve this! 👍

shuding added a commit that referenced this issue Dec 23, 2021
nevilm-lt pushed a commit to nevilm-lt/swr-1 that referenced this issue Apr 22, 2022
nevilm-lt pushed a commit to nevilm-lt/swr-1 that referenced this issue Apr 22, 2022
nevilm-lt pushed a commit to nevilm-lt/swr-1 that referenced this issue Apr 22, 2022
nevilm-lt pushed a commit to nevilm-lt/swr-1 that referenced this issue Apr 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

6 participants