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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 14:57:44