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

T3-app使用useSuspenseQuery构建超时,如何正确使用?

T3 App构建超时:useSuspenseQuery的正确用法与问题分析

问题背景

我开发T3 App时遇到构建超时错误,将代码中:

const [leads] = api.lead.getLeads.useSuspenseQuery();

替换为:

const { data: leads } = api.lead.getLeads.useQuery();

后构建成功。想明确两个问题:

  1. 如何正确使用useSuspenseQuery?我操作错在哪里?
  2. 除了无需处理加载/错误状态,useSuspenseQuery还有哪些优势?

完整错误信息

Failed to build /page: / (attempt 1 of 3) because it took more than 60 seconds. Retrying again shortly.
Failed to build /page: / (attempt 2 of 3) because it took more than 60 seconds. Retrying again shortly.
Failed to build /page: / after 3 attempts.
Export encountered an error on /page: /, exiting the build.
⨯ Static worker exited with code: 1 and signal: null

相关代码

首页服务端组件

import { api, HydrateClient } from "@/trpc/server";
import { Leads } from "./_components/Leads/Leads";

export default async function Home() {
  await api.lead.getLeads.prefetch();

  return (
    <HydrateClient>
      <Leads />
    </HydrateClient>
  );
}

使用useSuspenseQuery的客户端组件LeadsTable

"use client";

import { api } from "@/trpc/react";
import { Table } from "../../UI";
import { columns } from "./LeadsTable.columns";

export const LeadsTable = () => {
  const [leads] = api.lead.getLeads.useSuspenseQuery();

  return (
    <Table
      rows={leads}
      columns={columns}
      initialState={{
        sorting: {
          sortModel: [
            {
              field: "id",
              sort: "desc",
            },
          ],
        },
      }}
    />
  );
};

问题分析与解决

1. 错误原因:缺少Suspense边界

你直接在客户端组件中使用useSuspenseQuery,但没有给该组件套上React的Suspense边界。在Next.js静态构建(SSG)过程中,客户端组件触发Suspense后没有对应的 fallback 处理,导致构建进程陷入无限等待,最终超时失败。

2. 正确使用useSuspenseQuery的方式

要让useSuspenseQuery正常工作,必须给使用它的组件添加Suspense边界:

方式一:在父客户端组件中包裹

如果Leads是客户端组件,修改代码如下:

"use client";
import { Suspense } from "react";
import { LeadsTable } from "./LeadsTable";

export const Leads = () => {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <LeadsTable />
    </Suspense>
  );
};

方式二:在服务端首页组件中包裹

直接在服务端的Home组件里给Leads加上Suspense边界:

import { Suspense } from "react";
import { api, HydrateClient } from "@/trpc/server";
import { Leads } from "./_components/Leads/Leads";

export default async function Home() {
  await api.lead.getLeads.prefetch();

  return (
    <HydrateClient>
      <Suspense fallback={<div>加载中...</div>}>
        <Leads />
      </Suspense>
    </HydrateClient>
  );
}

这样处理后,静态构建时就能正确识别Suspense逻辑,不会出现超时,同时客户端也能正常读取服务端预取的数据。

3. useSuspenseQuery的额外优势

除了不用手动处理isLoading、error状态外,它还有这些实用特性:

  • 代码更简洁:直接获取数据,无需写大量条件渲染分支,逻辑更清晰。
  • 兼容React Suspense生态:可以配合代码分割、懒加载等特性,实现更细粒度的加载状态控制。
  • 数据优先的渲染逻辑:组件仅在数据就绪后渲染,避免了未就绪数据导致的UI异常。
  • 自动状态清理:组件卸载时会自动清理Suspense相关状态,降低内存泄漏风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 07:03:16