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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 23:48:10