React Query未捕获404错误致页面完全无法渲染求助
问题
运行指定仓库代码时,页面完全无法渲染,useQuery钩子未像参考视频那样捕获错误,直接导致页面崩溃。
相关代码如下:
请求函数
export const fetchCars = async () => { const resp = await fetch(CARS_ENDPOINT.slice(0, -3)); // 故意制造404错误 console.log(resp); if (!resp.ok) throw new Error("Failed to fetch"); return await resp.json(); };
自定义Hook
export const useCars = ({ onSuccess, onError } = {}) => useQuery({ queryKey: [STORAGE_KEY], queryFn: fetchCars, onSuccess, onError, });
页面组件
const CarsListPage = () => { const deleteMutation = useDelete(); const deleteHandler = (id) => { deleteMutation.mutate(id); }; const { data, isLoading, error, isError, isFetching } = useCars(); let component = null; if (isLoading || isFetching) { component = <CircularProgress />; } else if (isError) { component = <p>Error: {JSON.stringify(error)}</p>; } else { component = <CarsList cars={data} deleteHandler={deleteHandler} />; } return ( <> <Typography variant="h3" component="h2"> Cars </Typography> {component} </> ); }; export default CarsListPage;
补充信息:使用@tanstack/react-query版本为^4.26.1,报错日志如下:
query.ts:444 Error: Failed to fetch at Object.fetchCars [as queryFn] (index.js?t=1678250720657:6:23) onError @ query.ts:444 reject @ retryer.ts:112 (anonymous) @ retryer.ts:174 Promise.catch (async) run @ retryer.ts:154 createRetryer @ retryer.ts:204 fetch @ query.ts:456 fetchOptimistic @ queryObserver.ts:305 fetchOptimistic @ suspense.ts:50 useBaseQuery @ useBaseQuery.ts:97 useQuery @ useQuery.ts:139 useCars @ queries.js?t=1678251342413:11 CarsListPage @ List.jsx:16 renderWithHooks @ react-dom.development.js:16305 mountIndeterminateComponent @ react-dom.development.js:20074 beginWork @ react-dom.development.js:21587 beginWork$1 @ react-dom.development.js:27426 performUnitOfWork @ react-dom.development.js:26557 workLoopSync @ react-dom.development.js:26466 renderRootSync @ react-dom.development.js:26434 performConcurrentWorkOnRoot @ react-dom.development.js:25738 workLoop @ scheduler.development.js:266 flushWork @ scheduler.development.js:239 performWorkUntilDeadline @ scheduler.development.js:533 2useBaseQuery.ts:109 Uncaught Error: Failed to fetch at Object.fetchCars [as queryFn] (index.js?t=1678250720657:6:23) fetchCars @ index.js?t=1678250720657:6 react-dom.development.js:18687 The above error occurred in the <CarsListPage> component: at CarsListPage (http://localhost:5173/src/pages/List.jsx?t=1678251342413:25:26) at RenderedRoute (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=544e5302:3026:5) at Outlet (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=544e5302:3311:26) at div at http://localhost:5173/node_modules/.vite/deps/chunk-27RC25JA.js?v=544e5302:3619:51 at Container3 (http://localhost:5173/node_modules/.vite/deps/chunk-27RC25JA.js?v=544e5302:7647:19) at main at Layout (http://localhost:5173/src/components/Layout.jsx:35:7) at RenderedRoute (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=544e5302:3026:5) at Routes (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=544e5302:3371:5) at QueryClientProvider (http://localhost:5173/node_modules/.vite/deps/chunk-FQOZDGIW.js?v=544e5302:2790:3) at UIProvider (http://localhost:5173/src/components/contexts/UI.context.jsx:30:3) at InnerThemeProvider (http://localhost:5173/node_modules/.vite/deps/chunk-27RC25JA.js?v=544e5302:6121:17) at ThemeProvider2 (http://localhost:5173/node_modules/.vite/deps/chunk-27RC25JA.js?v=544e5302:4746:5) at ThemeProvider3 (http://localhost:5173/node_modules/.vite/deps/chunk-27RC25JA.js?v=544e5302:6129:5) at Router (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=544e5302:3318:15) at BrowserRouter (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=544e5302:3731:5) at App Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries. logCapturedError @ react-dom.development.js:18687 update.callback @ react-dom.development.js:18720 callCallback @ react-dom.development.js:13923 commitUpdateQueue @ react-dom.development.js:13944 commitLayoutEffectOnFiber @ react-dom.development.js:23391 commitLayoutMountEffects_complete @ react-dom.development.js:24688 commitLayoutEffects_begin @ react-dom.development.js:24674 commitLayoutEffects @ react-dom.development.js:24612 commitRootImpl @ react-dom.development.js:26823 commitRoot @ react-dom.development.js:26682 finishConcurrentRender @ react-dom.development.js:25892 performConcurrentWorkOnRoot @ react-dom.development.js:25809 workLoop @ scheduler.development.js:266 flushWork @ scheduler.development.js:239 performWorkUntilDeadline @ scheduler.development.js:533 react-dom.development.js:26923 Uncaught Error: Failed to fetch at Object.fetchCars [as queryFn] (index.js?t=1678250720657:6:23)
解决方案
核心原因
从报错日志能看出,错误是在Suspense模式下抛出的。React Query v4默认不会在Suspense模式下把错误封装到isError/error状态中,而是直接抛出未捕获错误,导致组件崩溃。
解决办法
关闭Suspense模式
若不需要Suspense,创建QueryClient时显式禁用:const queryClient = new QueryClient({ defaultOptions: { queries: { suspense: false, // 关闭Suspense模式 }, }, });这样useQuery会回到常规模式,错误会被捕获并更新
isError和error状态,组件就能正常渲染错误提示。添加错误边界组件
若要保留Suspense模式,必须用错误边界捕获抛出的错误。创建一个错误边界组件:class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, errorInfo) { console.error("错误边界捕获到异常:", error, errorInfo); } render() { if (this.state.hasError) { return <p>请求出错:{this.state.error.message}</p>; } return this.props.children; } }用它包裹页面组件或路由:
<ErrorBoundary> <CarsListPage /> </ErrorBoundary>检查全局配置
确认QueryClientProvider正确包裹整个应用,若全局配置了suspense: true,需要调整默认选项。
额外说明
视频中未出现该问题,大概率是因为视频代码未启用Suspense模式,或版本配置不同。若需在Suspense下处理错误,错误边界是React官方推荐的方案,React Query在Suspense模式下不会自动处理错误抛出。
内容的提问来源于stack exchange,提问作者user1775718
相关产品推荐
相关产品推荐

