使用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
相关产品推荐
相关产品推荐

