swr icon indicating copy to clipboard operation
swr copied to clipboard

Returning undefined from fetcher function causes suspense to loop infinitely.

Open kiranmarshall opened this issue 2 years ago • 1 comments

Bug report

Description / Observed Behavior

I would like to cancel the fetcher function before it is executed, and return undefined to useSwr so that I can use a fallback return type (empty array or object, for example) for the UI.

The return type of the fetcher is Promise<ExpectedReturn[] | undefined>. Annoyingly this pattern has worked in all cases up until now, on one specific API call. Changing undefined to false and early returning false from the fetcher function produces the expected behaviour.

What kind of issues did you encounter with SWR?

Receiving undefined from the fetcher caused Swr to loop infinitely, but never threw an error or warning of any kind.

Expected Behavior

Receiving undefined from the fetcher function should cause const { data } = useSwr... to evaluate to undefined, and the fallback of return { data: data || [] } should be returned.

Repro Steps / Code Example

This is production code, so it is heavily redacted. Annoyingly this is happening in one specific case making it hard for me to diagnose.

import useSwr from 'swr';

const fetcher = async (url: string, token: string): Promise<ExpectedReturn[] | undefined> => {
   if (exitCondition) return;
  
   // conditionally passing token to fetcher, this is a one off, but may be important
   const config = { headers: { Authorization: `Bearer ${token}` } };
   return await base.get(url, config).then(responseHandler);
};

export const useSwrWrapper = ({ token, ...params }: Params) => {
   const url = `/my-url/${paramsAsQueryString}`;
   const { data } = useSwr([url, token], fetcher, { suspense: true, revalidateOnFocus: false });

   return { data: data || [] };
};

Or share your code snippet or a CodeSandbox link is also appreciated!

Additional Context

As highlighted in the code block, we are passing a token to the axios fetcher if it does exist. This has not cause issues elsewhere but may be of significance.

The useSwrWrapper is not being called illegally/break any rules of hooks from the function component.

Dependencies/Dev dependencies that may be relevant:

"react": "^17.0.0",
"react-dom": "^17.0.0",
"@types/node": "^16.11.10",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"swr": "^1.1.2",
"typescript": "^4.3.2",
"vite": "^2.6.4"

SWR version. Add any other context about the problem here.

Please feel free to let me know if this is in the wrong place. First public issue I have posted.

kiranmarshall avatar Jun 07 '22 09:06 kiranmarshall

This is the behavior by design, because we use undefined in SWR as the “no data has been resolved” state. And then, in Suspense that will naturally result in the suspending UI as SWR will try to resolve the data before rendering.

I’d recommend returning null in those cases to explicitly say that fetching has ended with an empty state.

shuding avatar Jul 04 '22 22:07 shuding