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

为何shadcn/ui DataTable在TanStack Query失效后不重新渲染?

解决Shadcn DataTable删除记录后不更新的问题

问题场景

使用Next.js、TanStack React Query和Shadcn UI开发,包含Substance List、Shadcn DataTable、Shadcn Columns三个组件。执行删除操作后,DataTable无法自动重新渲染以同步数据变化。已在Columns组件中触发删除并调用queryClient.invalidateQueries({ queryKey: ["substances"] }),但表格仍无更新。

核心错误原因

在Columns组件的actions列cell函数中,你新建了一个QueryClient实例:

const queryClient = new QueryClient();

这个实例和Substances组件中useQuery使用的全局QueryClient实例不是同一个,所以调用invalidateQueries只会清空这个局部实例的缓存,根本不会触发全局缓存的刷新,自然无法让Substances组件里的useQuery重新获取数据。

修复步骤

1. 使用全局QueryClient实例

替换new QueryClient()为React Query提供的useQueryClient()钩子,获取应用全局的QueryClient实例。

2. 确保Hook符合规则

保证useQueryClient和useMutation在cell函数的最顶层调用,符合React Hook的使用规则。

修改后的Columns组件代码

"use client";
import { useRouter } from "next/navigation";
import axios from "axios";
import toast from "react-hot-toast";

// 导入useQueryClient钩子,而非QueryClient类
import { useMutation, useQueryClient } from "@tanstack/react-query";

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";
import Link from "next/link";

import { Substance } from "@prisma/client";

export const columns: ColumnDef<Substance>[] = [
  {
    accessorKey: "name",
    header: "名称",
    cell: ({ row }) => {
      const substance = row.original;
      return (
        <Link
          href={`/substances/${substance.id}`}
          className="underline text-sky-700"
        >
          {substance.name}
        </Link>
      );
    },
  },
  {
    accessorKey: "type",
    header: "类型",
  },
  {
    accessorKey: "EVcode",
    header: "EV编码",
  },
  {
    accessorKey: "status",
    header: "状态",
  },
  {
    id: "actions",
    cell: ({ row }) => {
      const substance = row.original;
      const router = useRouter();
      // 使用useQueryClient获取全局实例
      const queryClient = useQueryClient();

      const handleEdit = (substanceId: string) => {
        router.push(`/substances/${substanceId}`);
      };

      const { mutate: handleDeleteMutation } = useMutation({
        mutationFn: async (substanceId: string) => {
          await axios.delete("/api/substances", { data: { substanceId } });
        },
        onSuccess: () => {
          // 现在调用的是全局QueryClient的invalidateQueries
          queryClient.invalidateQueries({ queryKey: ["substances"] });
          toast.success("物质已删除");
        },
        onError: () => {
          toast.error("删除失败,请重试");
        },
      });

      return (
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="ghost" className="h-8 w-8 p-0">
              <span className="sr-only">打开菜单</span>
              <MoreHorizontal className="h-4 w-4" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuLabel>操作</DropdownMenuLabel>
            <DropdownMenuItem onClick={() => handleEdit(substance.id)}>
              编辑
            </DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem>复制</DropdownMenuItem>
            <DropdownMenuItem
              onClick={() => handleDeleteMutation(substance.id)}
            >
              删除
            </DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      );
    },
  },
];

额外检查点

  • 确保你的Next.js项目已经正确配置了React Query的全局Provider(通常在layout.tsx中),示例配置:
// app/layout.tsx
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>
        <QueryClientProvider client={queryClient}>
          {children}
        </QueryClientProvider>
      </body>
    </html>
  );
}
  • Substances组件中确保data正确传递给DataTable,并且没有在渲染时做不必要的缓存或深拷贝,导致数据变化无法被检测到。

内容的提问来源于stack exchange,提问作者Aro

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 01:35:22