Бесконечный цикл повторов React-Query

Столкновение с бесконечным рендерингом при сбое запроса с использованием реакции-запроса. useQuery следует повторно получать только в случае изменения queryKey или при ошибке запроса согласно параметру retry.

Почему queryFn выполняется повторно?

Воспроизводимый пример: 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.info('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>
);

В конце концов, мне нужно визуализировать <Component /> только после завершения загрузки useFailingQuery() и визуализировать скелет всей страницы во время ее загрузки.

🤔 А знаете ли вы, что...
React обеспечивает высокую производительность благодаря эффективной обработке изменений DOM.


157
2

Ответы:

Хотя мне не удалось разобраться с циклом useQuery(), обходной путь — всегда отображать компонент:

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

  return <>
    {isLoading && <span>Loading...</span>}
    <Component />
  </>;
};

Решено

Существует параметр retryOnMount (https://tanstack.com/query/v5/docs/framework/react/reference/useQuery#:~:text=retryOnMount%3A%20boolean), который по умолчанию имеет значение true. Это то, что вызывает ваш цикл. Когда <Component /> монтируется, он запускает повторную выборку, повторная выборка делает isLoading истинным для рендеринга, который отключает компонент, следующий рендер приводит к тому, что isLoading становится ложным, что снова монтирует компонент и изменяет isLoading на true.

Решение вашей проблемы — установить для retryOnMount значение false либо в глобальной конфигурации, либо в конфигурации для конкретного запроса.

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