Search code examples
reactjsreact-query

React-Query infinite retry loop


Facing an infinite render when a query fails using react-query. useQuery should only re-fetch if queryKey changes, or on request failure according to retry parameter.

Why is queryFn being re-executed?

Reproducible example: https://stackblitz.com/edit/ilias-react-query-loop?file=src%2Fmain.tsx

const queryClient = new QueryClient({
  defaultOptions: { queries: { retry: false } },
});

const useFailingQuery = () =>
  useQuery({
    queryKey: ['static'],
    queryFn() {
      console.log('Fetching...');
      throw new Error('Fail');
      return {};
    },
  });

const Component = () => {
  useFailingQuery();
  return <h1>Component</h1>;
};

const App = () => {
  const { isLoading } = useFailingQuery();

  // This causes infinite query retry
  if (isLoading) {
    return <span>Loading...</span>;
  }

  return <Component />;
};

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
    </QueryClientProvider>
  </React.StrictMode>
);

In the end, I need to render <Component /> only when useFailingQuery() is finished loading, and render a page-wide skeleton while it is loading.


Solution

  • There is a setting called retryOnMount (https://tanstack.com/query/v5/docs/framework/react/reference/useQuery#:~:text=retryOnMount%3A%20boolean) that is true by default. This is what is causing your loop. When the <Component /> mounts it triggers a refetch, the refetch makes isLoading true for a render, which unmounts the component, next render causes isLoading to be false, which mounts the component again and changes the isLoading to true.

    The solution to your problem is setting retryOnMount to false in either the global config or the config for the particular query.

    const queryClient = new QueryClient({
      defaultOptions: { queries: { retry: false, retryOnMount: false } },
    });