You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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状态中,而是直接抛出未捕获错误,导致组件崩溃。

解决办法

  1. 关闭Suspense模式
    若不需要Suspense,创建QueryClient时显式禁用:

    const queryClient = new QueryClient({
      defaultOptions: {
        queries: {
          suspense: false, // 关闭Suspense模式
        },
      },
    });
    

    这样useQuery会回到常规模式,错误会被捕获并更新isError和error状态,组件就能正常渲染错误提示。

  2. 添加错误边界组件
    若要保留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>
    
  3. 检查全局配置
    确认QueryClientProvider正确包裹整个应用,若全局配置了suspense: true,需要调整默认选项。

额外说明

视频中未出现该问题,大概率是因为视频代码未启用Suspense模式,或版本配置不同。若需在Suspense下处理错误,错误边界是React官方推荐的方案,React Query在Suspense模式下不会自动处理错误抛出。

内容的提问来源于stack exchange,提问作者user1775718

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:35:08