在React组件中使用tRPC的getUserFiles时出现_context未定义错误
问题:调用tRPC的getUserFiles时出现"Cannot read properties of undefined (reading '_context')"错误,且数据类型为any
- 错误触发位置:Dashboard组件的
const { data: files, isLoading } = trpc.getUserFiles.useQuery();代码行 - 异常表现:预期返回类型化的文件数据,但
files类型显示为any - 报错信息:Cannot read properties of undefined (reading '_context')
Prisma Schema定义
generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") directUrl = env("DIRECT_URL") } model User { id String @id @unique email String @unique File File[] stripeCustomerId String? @unique @map(name: "stripe_customer_id") stripeSubscriptionId String? @unique @map(name: "stripe_subscription_id") stripePriceId String? @map(name: "stripe_price_id") stripeCurrentPeriodEnd DateTime? @map(name: "stripe_current_period_end") } enum UploadStatus { PENDING PROCESSING FAILED SUCCESS } model File { id String @id @default(cuid()) name String uploadStatus UploadStatus @default(PENDING) url String key String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt User User? @relation(fields: [userId], references: [id]) userId String? }
getUserFiles的tRPC路由实现
import { db } from "@/db"; import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"; import { TRPCError } from "@trpc/server"; import { privateProcedure, publicProcedure, router } from "./trpc"; export const appRouter = router({ authCallback: publicProcedure.query(async () => { // 从KindeServer会话获取用户 const { getUser } = getKindeServerSession(); const user = await getUser(); // 用户未认证则抛出错误 if (!user || !user.id || !user.email) throw new TRPCError({ code: "UNAUTHORIZED" }); // 检查用户是否已存在于数据库 const dbUser = await db.user.findFirst({ where: { id: user.id, }, }); if (!dbUser) { // 在数据库中创建用户 await db.user.create({ data: { id: user.id, email: user.email, }, }); } return { success: true }; }), // 获取用户文件 getUserFiles: privateProcedure.query(async ({ ctx }) => { // 从上下文提取用户ID const { userId } = ctx; // 查询数据库中属于该用户的文件 return await db.file.findMany({ where: { userId, }, }); }), }); export type AppRouter = typeof appRouter;
私有过程(privateProcedure)实现
import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"; import { TRPCError, initTRPC } from "@trpc/server"; const t = initTRPC.create(); const middleware = t.middleware; const isAuth = middleware(async (opts) => { const { getUser } = getKindeServerSession(); const user = await getUser(); if (!user || !user.id) { throw new TRPCError({ code: "UNAUTHORIZED" }); } return opts.next({ ctx: { userId: user.id, user, }, }); }); export const router = t.router; export const publicProcedure = t.procedure; export const privateProcedure = t.procedure.use(isAuth);
报错的Dashboard组件代码
import { trpc } from "@/app/_trpc/client"; import UploadButton from "./UploadButton"; import { Ghost } from "lucide-react"; const Dashboard = () => { const { data: files, isLoading } = trpc.getUserFiles.useQuery(); return ( <main className="mx-auto max-w-7xl md:p-10"> <div className="mt-8 flex flex-col items-start justify-between gap-4 border-b border-gray-200 pb-5 sm:flex-row sm:items-center sm:gap-0"> <h1 className="mb-3 font-bold text-5xl text-gray-900">我的文件</h1> <UploadButton /> </div> {/* 展示所有用户文件 */} {files && files?.length !== 0 ? ( <div></div> ) : isLoading ? ( <div></div> ) : ( <div className="mt-16 flex flex-col items-center gap-2"> <Ghost className="h-8 text-zinc-800" /> <h3 className="font-semibold text-xl"> 上传你的第一个PDF吧。 </h3> </div> )} </main> ); }; export default Dashboard;
修复方案
1. 补全客户端类型配置
确保tRPC客户端正确导入AppRouter类型,否则会丢失类型推断(导致any类型)。客户端配置文件(如@/app/_trpc/client.ts)需包含:
import { createTRPCReact } from "@trpc/react-query"; import type { AppRouter } from "@/path/to/your/appRouter"; export const trpc = createTRPCReact<AppRouter>();
2. 修复_context未定义问题
该错误通常是客户端与服务器连接异常或上下文传递失败导致:
- 确认根布局/App组件中正确配置了tRPC Provider,包含客户端实例和React Query查询客户端
- 检查服务器端tRPC上下文初始化逻辑,确保
isAuth中间件能正常传递userId到后续过程 - 验证Kinde认证会话在服务器端可正常获取用户信息,避免
getUser()返回undefined导致上下文未注入
3. 验证中间件逻辑
确认isAuth中间件在调用opts.next()时正确传递了包含userId和user的上下文对象,避免因中间件抛出错误导致上下文未设置。
内容的提问来源于stack exchange,提问作者alpaca pwaa
相关产品推荐
相关产品推荐

