skip to Main Content

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.

2

Answers


  1. Chosen as BEST ANSWER

    While I couldn't figure out the useQuery() loop, a workaround is to always render the component:

    const App = () => {
      const { isLoading } = useFailingQuery();
    
      return <>
        {isLoading && <span>Loading...</span>}
        <Component />
      </>;
    };
    

  2. 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 } },
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search