使用react-query时请求失败引发无限渲染循环问题排查
问题原因分析
你遇到的无限循环问题,核心原因是两个组件(App和Component)重复订阅了同一个queryKey的查询,再加上React StrictMode的双重渲染机制,以及react-query默认的staleTime=0配置,触发了组件挂载-卸载的循环:
- 初始渲染
App时,调用useFailingQuery进入加载状态,渲染Loading...,Component未挂载。 - 查询失败后,
isLoading变为false,App切换渲染Component。 Component挂载后调用useFailingQuery,由于react-query默认staleTime=0(缓存立即过期),会重新触发一次查询,此时isLoading再次变为true。App感知到isLoading变化,重新渲染并切换回Loading...,Component被卸载,其订阅的查询被取消。- 上述流程反复触发,形成无限循环。
解决方案
方案1:提升查询逻辑,避免重复订阅
将useFailingQuery的调用统一放在父组件App中,通过props传递查询状态,避免子组件重复触发查询:
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } }, }); const useFailingQuery = () => useQuery({ queryKey: ['static'], queryFn() { console.log('Fetching...'); throw new Error('Fail'); return {}; }, }); const Component = () => { return <h1>Component</h1>; }; const App = () => { const { isLoading, isError } = useFailingQuery(); if (isLoading) { return <span>Loading...</span>; } // 处理错误状态,避免查询失败后仍渲染Component if (isError) { return <span>查询失败,请稍后重试</span>; } return <Component />; }; ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <QueryClientProvider client={queryClient}> <App /> </QueryClientProvider> </React.StrictMode> );
方案2:配置staleTime避免不必要的重新查询
如果确实需要在多个组件中调用同一个自定义Hook,可以设置staleTime让缓存保持有效,避免组件挂载时重复触发查询:
const useFailingQuery = () => useQuery({ queryKey: ['static'], queryFn() { console.log('Fetching...'); throw new Error('Fail'); return {}; }, staleTime: Infinity, // 缓存永远不过期,除非主动失效 retry: false, });
额外建议:完善状态判断
原代码未处理查询失败的isError状态,即使查询失败仍会渲染Component,这既不符合业务逻辑,也是触发循环的诱因。建议始终在逻辑中覆盖isLoading、isError、isSuccess等全量状态,避免无效的组件切换。
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

