reactjstypescriptaxiosreact-suspense

Infinite loop when using React Suspense and Axios data fetch


I'm trying to fetch data with Axios and display it in a suspense element, like in this tutorial: https://dev.to/darkmavis1980/a-practical-example-of-suspense-in-react-18-3lln

However, the wrapPromise function gets me in an endless loop:

function wrapPromise(promise: Promise<any>) {
    let status = 'pending';
    let response : any;
  
    const suspender = promise.then(
      res => {
        status = 'success';
        response = res;
      },
      err => {
        status = 'error';
        response = err;
      },
    );
  
    const handler = {
      pending: () => {
        throw suspender;
      },
      error: () => {
        throw response;
      },
      default: () => response,
    };
  
    const read = () => {
        //@ts-ignore
      const result = handler[status] ? handler[status]() : handler.default();
      return result;
    };
  
    return { read };
  }
  
  export default wrapPromise;

I'm expecting the line

pending: () => {
        throw suspender;
      }

to be called once (or a few times) in the beginning, but instead its called forever... I've tried rewriting this code to return the result but with no success...

I'm calling the wrapPromise() function like this (simplified):

const dataFetch = (id: number) => {
    const logsPromise: Promise<Array<Log>> = fetchLogs(id)
    return {
        logs: wrapPromise(logsPromise),
    }
}


function fetchLogs(id: number): any {
    return axios
        .get(`myurl/getlogs?id=${id}`)
        .then((r) => r.data as Array<Log>)
        .catch((err) => console.log(err))
}

const logTable = function logTable({ id }: logProps) {
     return (
            <Suspense
                    fallback={<FallbackComponent />}
                >
                    <LogResult id={id} />
                </Suspense>
        )
}

const LogResult  = function MyLogs({ id }: LogResultProps) {
    let logs: any = dataFetch(id).logs.read() 
    return <LogComponent logs={logs as Array<Log>} />
}

Solution

  • I've found a solution for this problem by ditching the wrapPromise() and dataFetch() functions, and using https://swr.vercel.app/ instead.

    The LogResult component becomes:

    const LogResult  = function MyLogs({ id }: LogResultProps) {
        const fetcher = (id: number) => fetchLogs(id)
        const { data: logs } = useSWR(
            id as any,
            fetcher,
            { suspense: true}
          );
        return <LogComponent logs={logs as Array<Log>} />
    }
    

    Here is a more detailled article: https://dev.to/darkmavis1980/using-swr-hook-with-suspense-in-react-18-1clk