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

使用tRPC的useInfiniteQuery时因cursor参数引发TRPCClientError

解决tRPC useInfiniteQuery触发TRPCClientError(cursor参数必填)的问题

问题原因

你遇到的400错误是因为useInfiniteQuery初始调用时会默认传递undefined作为cursor参数,但你的tRPC后端procedure里把cursor声明成了必填的字符串类型(比如用z.string()),导致zod校验失败,抛出invalid_type错误。而之前用useQuery时,你可能没有传递cursor参数,或者调用的是不需要cursor的逻辑,所以没触发校验问题。

解决方案

方案1:修改后端procedure的schema,将cursor设为可选

这是最规范的做法,符合tRPC官方文档中“初始调用无需传cursor”的说明。只需在zod schema里给cursor加上.optional():

import { z } from 'zod';
import { t } from '../trpc';

export const getPaginatedData = t.procedure
  .input(z.object({
    cursor: z.string().optional(), // 改为可选参数
    limit: z.number().default(10),
  }))
  .query(async ({ input }) => {
    // 处理cursor为undefined的情况:初始加载第一页
    const data = await yourDb.query.findMany({
      take: input.limit,
      // 只有当cursor存在时才设置游标查询
      ...(input.cursor && {
        skip: 1,
        cursor: { id: input.cursor },
      }),
    });

    // 返回数据和下一页游标(没有更多数据时返回null)
    return {
      data,
      nextCursor: data.length === input.limit ? data[data.length - 1].id : null,
    };
  });

方案2:前端初始调用时传合法的默认cursor值

如果不想修改后端,可在useInfiniteQuery的初始参数里传一个空字符串或后端能识别的默认值(需确保后端逻辑能处理该值):

const { data, fetchNextPage } = api.yourRoute.getPaginatedData.useInfiniteQuery(
  { cursor: '', limit: 10 }, // 初始传空字符串
  {
    getNextPageParam: (lastPage) => lastPage.nextCursor,
  }
);

额外说明

useInfiniteQuery的设计逻辑是:初始调用后,后续fetchNextPage会自动传递上一页返回的nextCursor。所以后端必须兼容cursor为undefined的情况,或者前端初始传合法默认值,才能避免校验错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:27:53