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