TanStack React Table实现确认删除状态并在useEffect中删除记录
TanStack React Table 实现确认删除状态与 useEffect 执行删除操作
1. 修改工具栏组件,添加确认删除触发逻辑
更新DataTableRowSelectionToolbar组件,新增回调函数传递用户确认删除的操作,同时调整对话框的触发逻辑:
import { useState } from "react"; import { Ingrediant } from "@/types"; import { Table } from "@tanstack/react-table"; import { Button } from "@/Components/ui/button"; import { Trash2 } from "lucide-react"; import { Alert, AlertDescription } from "@/Components/ui/alert"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/Components/ui/alert-dialog"; export default function DataTableRowSelectionToolbar({ table, onConfirmDelete, }: { table: Table<Ingrediant>; onConfirmDelete: () => void; }) { const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const selectedRowsCount = table.getSelectedRowModel().rows.length; const totalRowsCount = table.getFilteredRowModel().rows.length; return ( <div className="space-y-2 pt-4 w-full"> <div className="flex items-center justify-between"> <div className="text-sm text-muted-foreground"> {selectedRowsCount > 0 ? ( <> <span className="font-medium text-foreground"> {selectedRowsCount} </span>{" "} of{" "} <span className="font-medium text-foreground"> {totalRowsCount} </span>{" "} row(s) selected. </> ) : ( <> <span className="font-medium text-foreground"> {totalRowsCount} </span>{" "} rows total. </> )} </div> {selectedRowsCount > 0 && ( <Button variant="ghost" size="sm" onClick={() => table.resetRowSelection()} > Clear selection </Button> )} </div> {selectedRowsCount > 0 && ( <AlertDialog open={isDeleteDialogOpen} onOpenChange={setIsDeleteDialogOpen} > <Alert variant="destructive" className="w-full "> <AlertDialogTrigger asChild> <Button variant="destructive" size="icon" onClick={() => setIsDeleteDialogOpen(true)} > <Trash2 className="h-4 w-4 cursor-pointer" /> </Button> </AlertDialogTrigger> <AlertDescription className="inline-flex ml-3"> Delete selected rows </AlertDescription> </Alert> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle> Are you absolutely sure? </AlertDialogTitle> <AlertDialogDescription> This action cannot be undone. This will permanently delete the {selectedRowsCount}{" "} selected row(s) and remove their data from our servers. </AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel onClick={() => setIsDeleteDialogOpen(false)}>Cancel</AlertDialogCancel> <AlertDialogAction onClick={() => { setIsDeleteDialogOpen(false); onConfirmDelete(); }} > Delete </AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> )} </div> ); }
2. 父组件中实现状态监听与删除请求
在包含表格的父组件里,新增确认删除状态,通过useEffect监听状态变化,执行批量删除请求并刷新表格:
import { useState, useEffect, useRef } from "react"; import { useRouter } from "@inertiajs/react"; import { query } from "@/utils/query-builder"; import DataTableRowSelectionToolbar from "./DataTableRowSelectionToolbar"; import { useReactTable, getCoreRowModel, getFilteredRowModel, getPaginationRowModel } from "@tanstack/react-table"; export default function IngredientsTable() { const router = useRouter(); const isRendered = useRef(false); const [sorting, setSorting] = useState([]); const [columnFilters, setColumnFilters] = useState([]); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); const [shouldDelete, setShouldDelete] = useState(false); const [table] = useReactTable({ // 你的表格数据源、列配置等 getCoreRowModel: getCoreRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), onSortingChange: setSorting, onColumnFiltersChange: setColumnFilters, onPaginationChange: setPagination, }); // 监听删除确认状态,执行删除操作 useEffect(() => { if (!shouldDelete) return; const selectedIds = table.getSelectedRowModel().rows.map(row => row.original.id); router.post(route("ingredients.bulk-delete"), { ids: selectedIds }, { onSuccess: () => { setShouldDelete(false); table.resetRowSelection(); // 触发表格数据刷新 setPagination(prev => ({ ...prev, pageIndex: 0 })); }, onError: (errors) => { console.error("删除失败:", errors); setShouldDelete(false); } }); }, [shouldDelete, table, router]); // 原有的分页/排序/筛选逻辑 useEffect(() => { const queryBuilder = query(route(route().current()!)); if (isRendered.current) { const sortQuery = sorting.map( (sort) => (sort.desc ? "-" : "") + sort.id ); if (sortQuery.length > 0) queryBuilder.sort(...sortQuery); columnFilters.forEach((filter) => queryBuilder.filter(filter.id, filter.value as any) ); const page = pagination.pageIndex + 1; queryBuilder .page(page) .param("per_page", pagination.pageSize.toString()); if (queryBuilder.build()) router.get(queryBuilder.build(), undefined, { preserveState: true, preserveScroll: true, replace: true, }); } isRendered.current = true; }, [sorting, columnFilters, pagination]); return ( <div> <DataTableRowSelectionToolbar table={table} onConfirmDelete={() => setShouldDelete(true)} /> {/* 表格内容渲染 */} </div> ); }
3. Laravel后端处理批量删除
路由配置
Route::post('/ingredients/bulk-delete', [IngredientController::class, 'bulkDelete'])->name('ingredients.bulk-delete');
控制器方法
use Illuminate\Http\Request; use Spatie\QueryBuilder\QueryBuilder; use App\Models\Ingredient; public function bulkDelete(Request $request) { $request->validate([ 'ids' => 'required|array|exists:ingredients,id', ]); QueryBuilder::for(Ingredient::class) ->whereIn('id', $request->ids) ->delete(); return redirect()->back()->with('success', '选中记录已删除'); }
内容的提问来源于stack exchange,提问作者EL MAHDI BOUZKOURA
相关产品推荐
相关产品推荐

