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

Next.js动态路由中tRPC结合getServerSideProps实现SSR的问题

问题描述

我刚启动了一个基于完整T3栈(Next.js、Prisma、Tailwind、tRPC)的小型项目,遇到了以下问题:

背景:我在PlanetScale(pscale)中有一个artists表,包含字段name、email、address、id、url,该表关联着art表(字段artName、artPrice、artDimensions)。我希望根据艺术家的url参数,在pages/artists/[url].tsx页面展示对应艺术家的内容。

我在trpc/router/artist.ts中配置了路由:

export const artistRouter = router({
    // 根据url查询艺术家
    byUrl: publicProcedure
        .input(
            z.object({
                url: z.string(),
            })
        )
        .query(async ({ input }) => {
            const { url }  = input;
            const artist = await prisma.artist.findUnique({
                where: { url },
                select: defaultArtistSelect,
            });
            // 注:原代码中错误使用了dealer,此处修正为artist
            if (!artist) {
                throw new TRPCError({
                    code: 'NOT_FOUND',
                    message: `No artist with url '${url}'`,
                });
            }
            return artist;
        }),
});

在[url].tsx页面中,用客户端查询的方式获取数据会出现短暂加载状态,首次查询时数据为undefined:

const url = useRouter().query.url as string;
const { data: artist, isError, isLoading, isSuccess } = trpc.artist.byUrl.useQuery({ url });

我希望为该动态路由实现SSR,且统一使用tRPC(不想直接用Prisma查询,因为其他场景如管理视图已在使用tRPC),但始终无法让getServerSideProps与tRPC配合工作。

更新:后来发现了tRPC文档中的SSG Helpers,解决了getServerSideProps的问题,但现在请求速度非常慢。


解决方案

1. 正确使用tRPC的SSG Helpers实现SSR

首先确保你已按T3栈规范配置了SSG Helpers(示例路径:server/trpc/ssgHelpers.ts):

// server/trpc/ssgHelpers.ts
import { appRouter } from "./router";
import { createTRPCContext } from "./trpc";
import { createServerSideHelpers } from "@trpc/react-query/server";
import superjson from "superjson";

export const createSSGHelpers = async () => {
  return createServerSideHelpers({
    router: appRouter,
    ctx: await createTRPCContext({ req: null, res: null }),
    transformer: superjson,
  });
};

然后在[url].tsx的getServerSideProps中调用该Helper预取数据:

// pages/artists/[url].tsx
import { createSSGHelpers } from "../../server/trpc/ssgHelpers";
import { trpc } from "../../utils/trpc";
import { useRouter } from "next/router";

export async function getServerSideProps(context) {
  const { url } = context.params;

  const ssg = await createSSGHelpers();

  try {
    // 预取艺术家数据
    await ssg.artist.byUrl.prefetch({ url });
  } catch (error) {
    // 捕获NOT_FOUND错误,返回404
    return {
      notFound: true,
    };
  }

  return {
    props: {
      trpcState: ssg.dehydrate(),
    },
  };
}

export default function ArtistPage() {
  const router = useRouter();
  // 直接获取预取的数据,无客户端加载状态
  const { data: artist } = trpc.artist.byUrl.useQuery({ url: router.query.url as string });

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold mb-4">{artist.name}</h1>
      <p className="mb-2">邮箱:{artist.email}</p>
      <p className="mb-4">地址:{artist.address}</p>
      <h2 className="text-xl font-semibold mb-2">作品列表</h2>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        {artist.art.map((item) => (
          <div key={item.id} className="border p-3 rounded">
            <h3>{item.artName}</h3>
            <p>价格:{item.artPrice}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

2. 优化请求速度的方法

如果使用SSG Helpers后速度慢,可从以下几点优化:

  • 添加数据库索引:确保artists表的url字段添加唯一索引,提升findUnique查询效率。在Prisma Schema中修改:
    model Artist {
      id        String   @id @default(cuid())
      name      String
      email     String?
      address   String?
      url       String   @unique // 添加唯一索引
      art       Art[]
      createdAt DateTime @default(now())
      updatedAt DateTime @updatedAt
    }
    
    运行prisma db push或prisma migrate dev更新数据库。
  • 精简查询字段:确认defaultArtistSelect只包含页面所需字段,关联art表时按需获取数据,避免冗余查询。
  • 缓存查询结果:若艺术家数据不频繁更新,可在getServerSideProps中加入Redis等缓存逻辑,减少数据库查询次数。
  • 检查上下文初始化:确保createTRPCContext中没有重复创建Prisma客户端(T3栈默认已配置单例客户端,无需额外实例化)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:40:32