Столкновение с бесконечным рендерингом при сбое запроса с использованием реакции-запроса. 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() и визуализировать скелет всей страницы во время ее загрузки.





Хотя мне не удалось разобраться с циклом 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 } },
});
Используйте Саспенс? Та же идея