6

I am using SWR in a React.js application and I find myself needing to display the loading status of a request.

I created a helper function that extracts the loading status from an SWRResponse similar to what SWR provides in their documentation examples:

const isLoading = ({ data, error }: SWRResponse<any, any>): boolean => {
    return data === undefined && error === undefined;
}

I would like to create a wrapper hook, that always adds this information in the return value, similar to the following:

const useSWRWithLoading: SWRHook = (...args) => {
    const swrResponse = useSWR(...args);
    return { ...swrResponse, isLoading: isLoading(swrResponse) };
};

Since I used the builtin type SWRHook I have no support for the isLoading value.

How I tried solving the issue (without any success):

const useSWRWithLoading = (...args: Parameters<SWRHook>): ReturnType<SWRHook> & { isLoading: boolean } => {
    const swrResponse = useSWR(...args);

    return { ...swrResponse, isLoading: isLoading(swrResponse) };
};

or (this is pretty much the same thing as before)

type SWRHookWithLoading = (...args: Parameters<SWRHook>) => ReturnType<SWRHook> & { isLoading: boolean };

const useSWRWithLoading: SWRHookWithLoading = (...args) => {
    const swrResponse = useSWR(...args);

    return { ...swrResponse, isLoading: isLoading(swrResponse) };
};

One thing I noticed is that:

type Foo = Parameters<SWRHook>; // type Foo = never
type Bar = ReturnType<SWRHook>; // type Bar = SWRResponse<unknown,unknown>

And I don't know how to fix it.

If I try to make the SWRHookWithLoading Type a generic, I get an error that says: Type 'SWRHook' is not generic..

type SWRHookWithLoading<Data = any, Error = any> = (...args: Parameters<SWRHook<Data, Error>>) => ReturnType<SWRHook<Data, Error>> & { isLoading: boolean };

This is puzzling for me because the type definition for SWRHook is:

export declare type SWRHook = <Data = any, Error = any>(...args: readonly [Key] | readonly [Key, Fetcher<Data> | null] | readonly [Key, SWRConfiguration<Data, Error> | undefined] | readonly [Key, Fetcher<Data> | null, SWRConfiguration<Data, Error> | undefined]) => SWRResponse<Data, Error>;

which looks like a generic for me.

Xander
  • 161
  • 7

1 Answers1

1

I recommend creating a hook for each query, which then allows you to return custom values. In the example below, the function useUser returns the data property from the useSWR function as user, as well as custom properties isLoading and isError. isLoading is true when there is no error, but there is also no data. It is false if there is data, an error, or both.

function useUser (id) {
  const { data, error } = useSWR(`/api/user/${id}`, fetcher)

  return {
    user: data,
    isLoading: !error && !data,
    isError: error
  }
}

Source: SWR Docs

This approach also makes it easier to share queries between areas of your codebase.

NG235
  • 1,091
  • 12
  • 33