在Tanstack Table列定义中调用TRPC useMutation报错的解决方法
解决Shadcn DataTable中TRPC useMutation调用报错问题
错误原因
你在DropdownMenuItem的onClick回调里直接调用useMutation,违反了React Hook的核心规则:Hook只能在函数组件的顶层作用域或自定义Hook中调用,不能在事件处理函数、循环、条件判断等嵌套逻辑里使用。
解决方案
将TRPC的useMutation移到客户端组件的顶层,再把删除函数传递给列配置,避免在表格单元格的渲染逻辑中调用Hook。
步骤1:修改列配置,改为接收删除回调的函数
修改columns.tsx,把静态列数组改为返回列数组的函数,接收删除操作的回调参数:
"use client" import { ColumnDef } from "@tanstack/react-table" import { MoreHorizontal } from "lucide-react" import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu" export type Payment = { id: string; amount: number; status: string; email: string; } // 改为函数,接收删除回调 export const getColumns = (deletePayment: (id: string) => void): ColumnDef<Payment>[] => [ // 其他列配置... { id: "actions", cell: ({ row }) => { const payment = row.original return ( <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="ghost" className="h-8 w-8 p-0"> <span className="sr-only">Open menu</span> <MoreHorizontal className="h-4 w-4" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> <DropdownMenuLabel>Actions</DropdownMenuLabel> <DropdownMenuItem onClick={() => deletePayment(payment.id)}> Delete </DropdownMenuItem> </DropdownMenuContent> </DropdownMenu> ) }, }, ]
步骤2:在客户端组件中定义Mutation并传递给表格
修改page.tsx,添加"use client"指令转为客户端组件,在顶层调用useMutation,并将删除函数传递给列配置:
"use client" import { useState, useEffect } from "react" import { Payment, getColumns } from "./columns" import { DataTable } from "./data-table" import { api } from "@/trpc/react" async function fetchPayments(): Promise<Payment[]> { // 实际项目中替换为TRPC查询或API请求 return [ { id: "728ed52f", amount: 100, status: "pending", email: "m@example.com", }, // 更多测试数据... ] } export default function DemoPage() { const [payments, setPayments] = useState<Payment[]>([]) // 初始化加载数据 useEffect(() => { fetchPayments().then(data => setPayments(data)) }, []) // 定义删除Mutation,放在组件顶层 const deleteMutation = api.transaction.delete.useMutation({ onSuccess: () => { // 删除成功后更新本地数据,实现表格实时刷新 setPayments(prev => prev.filter(payment => payment.id !== deleteMutation.variables?.id)) }, onError: (error) => { // 处理删除失败的逻辑,比如提示用户 console.error("删除支付记录失败:", error) } }) // 封装删除函数,传递给列配置 const handleDeletePayment = (id: string) => { deleteMutation.mutate({ id }) } const columns = getColumns(handleDeletePayment) return ( <div> <DataTable columns={columns} data={payments} /> </div> ) }
关键说明
- 把列配置改为函数,让它能接收外部传入的删除回调,避免在单元格渲染逻辑中直接调用Hook。
- 在客户端组件的顶层调用
useMutation,严格遵守React Hook的使用规则。 - 删除成功后通过
setPayments更新本地数据,让表格自动刷新,无需重新请求整个列表。
内容的提问来源于stack exchange,提问作者WindCheck
相关产品推荐
相关产品推荐

