Search code examples
next.jstrpct3

tRPC - nextjs - app router - build fail on timeout error when using useSuspenseQuery


I created T3-app and my build fail on timeout error. If I change this line:

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

to

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

the build pass.

How can I use useSuspenceQuery? What am I doing wrong? Besides not having a loading/error state, is there any other benefit of suspenceQuery?

the complete error:

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

this is the page component:

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>
  );
}

This is the leads table component where the useSuspenseQuery is at:

"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",
            },
          ],
        },
      }}
    />
  );
};

This is the entire repo: https://github.com/ItayTur/sohnim-io


Solution

  • Here are some steps and considerations to help you use useSuspenseQuery correctly and avoid build timeouts

    When using useSuspenseQuery, the component expects the data to be available immediately, and if it's not, it will suspend the rendering until the data is fetched.

    Home component

    import { api, HydrateClient } from "@/trpc/server";
    import { Leads } from "./_components/Leads/Leads";
    import { Suspense } from "react";
    
    export default async function Home() {
      await api.lead.getLeads.prefetch();
    
      return (
        <HydrateClient>
          // you can change the loading div to some nice loader component or else
          <Suspense fallback={<div>Loading...</div>}>
            <Leads />
          </Suspense>
        </HydrateClient>
      );
    }
    

    LeadsTable Component

    "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",
                },
              ],
            },
          }}
        />
      );
    };
    

    Explanation:

    1. Suspense Fallback: The Home component now includes a Suspense fallback. This ensures that the build process and the user experience have a fallback UI while the data is being fetched.

    2. useSuspenseQuery: The LeadsTable component uses useSuspenseQuery to fetch the data. This ensures that the component will suspend rendering until the data is available.

    Additional Considerations:

    • API Performance: Ensure that your API is performing well and responding quickly. Slow API responses can cause the build process to timeout.

    • Error Handling: Consider adding error handling to manage cases where the data fetching fails. This can be done using the useSuspenseQuery hook's error state.