我希望每个操作按钮都有自己的可扩展独立行。我已经到了一半了。我正在使用 tanstack 表 v8。但问题是,如果我单击一行中的任何可扩展按钮,则会触发同一行中的所有可扩展按钮。我不想要这样。每个操作都会自行触发并用新数据扩展一行。 是否可以使用 tanstack 表或任何其他方式?
到目前为止我尝试过的一切都在这个codesandbox中。
我从未使用过 Tanstack...快速查看文档后,它似乎不支持多个扩展的东西。
我手动处理:https://codesandbox.io/p/sandbox/goofy-shtern-forked-3kny3x
基本上,这个想法是有一个状态来控制行/单元格的扩展方式。
expandedRowState
就是这么做的,它保存了行的id、展开的列以及展开的内容。当单击展开时,我不只是展开,而是使用该列进行了一些检查。
App.tsx
import "./styles.css";
import {
ColumnDef,
VisibilityState,
flexRender,
getCoreRowModel,
getExpandedRowModel,
useReactTable,
} from "@tanstack/react-table";
import { useState } from "react";
import { expandableColumns, expandableData } from "./column-data";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[];
data: TData[];
expandedRowContent: any;
getRowCanExpand: (row: any) => boolean;
}
export function ExpandableTable<TData, TValue>({
columns,
data,
expandedRowContent,
getRowCanExpand,
}: DataTableProps<TData, TValue>) {
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
const table = useReactTable({
data,
columns,
getRowCanExpand,
state: {
columnVisibility,
},
autoResetPageIndex: false,
enableRowSelection: true,
onColumnVisibilityChange: setColumnVisibility,
getCoreRowModel: getCoreRowModel(),
getExpandedRowModel: getExpandedRowModel(),
});
return (
<div className="space-y-4">
<div className="rounded-md border">
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<th key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
);
})}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<>
<tr
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</td>
))}
</tr>
{row.getIsExpanded() && (
<tr>
{/* 2nd row is a custom 1 cell row */}
<td colSpan={row.getVisibleCells().length}>
{expandedRowContent[row.id].content}
</td>
</tr>
)}
</>
))
) : (
<tr>
<td colSpan={columns.length} className="h-24 text-center">
No results.
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
);
}
export default function App() {
const [expandedRowState, setExpandedRowState] = useState<any>([]);
const setExpandedRowStateById = (id: any, content: any, columnIndex: any) => {
expandedRowState[id] = { content, columnIndex };
setExpandedRowState([...expandedRowState]);
};
return (
<div className="App">
<h1>Expand Table Example</h1>
<h2>Start editing to see some magic happen!</h2>
<ExpandableTable
data={expandableData}
columns={expandableColumns(expandedRowState, setExpandedRowStateById)}
expandedRowContent={expandedRowState}
getRowCanExpand={() => true}
/>
</div>
);
}
列数据.tsx
export const expandableColumns = (expandedRowState: any, setExpandedRowState: any) => {
return [
{
accessorKey: "firstName",
header: "First Name",
cell: ({ row, getValue }: any) => (
<div
style={{
paddingLeft: `${row.depth * 2}rem`,
}}
>
{row.getCanExpand() ? (
<button
{...{
onClick: () => {
if (!row.getIsExpanded() || (row.getIsExpanded() && expandedRowState[row.id].columnIndex == 0)) {
row.getToggleExpandedHandler()();
}
setExpandedRowState(row.id, <p>FINGER EMOJI - {row.original.firstName}</p>, 0);
},
style: { cursor: "pointer" },
}}
>
{row.getIsExpanded() && expandedRowState[row.id].columnIndex == 0 ? "👇" : "👉"}
</button>
) : (
"🔵"
)}
{getValue()}
</div>
),
footer: (props: { column: { id: any } }) => props.column.id,
},
{
accessorFn: (row: { lastName: any }) => row.lastName,
id: "lastName",
cell: ({ row, getValue }: any) => (
<div
style={{
paddingLeft: `${row.depth * 2}rem`,
}}
>
{row.getCanExpand() ? (
<button
{...{
onClick: () => {
if (!row.getIsExpanded() || (row.getIsExpanded() && expandedRowState[row.id].columnIndex == 1)) {
row.getToggleExpandedHandler()();
}
setExpandedRowState(row.id, <p>FLASHLIGHT EMOJI - {row.original.lastName}</p>, 1);
},
style: { cursor: "pointer" },
}}
>
{row.getIsExpanded() && expandedRowState[row.id].columnIndex == 1 ? "♟" : "🔦"}
</button>
) : (
"🔵"
)}
{getValue()}
</div>
),
header: () => <span>Last Name</span>,
footer: (props: { column: { id: any } }) => props.column.id,
},
{
accessorKey: "age",
header: () => "Age",
footer: (props: { column: { id: any } }) => props.column.id,
},
{
accessorKey: "visits",
header: () => <span>Visits</span>,
footer: (props: { column: { id: any } }) => props.column.id,
},
{
accessorKey: "status",
header: "Status",
footer: (props: { column: { id: any } }) => props.column.id,
},
{
accessorKey: "progress",
header: "Profile Progress",
footer: (props: { column: { id: any } }) => props.column.id,
},
];
};
export const expandableData = [
{
firstName: "Marquis",
lastName: "Runolfsdottir",
age: 36,
visits: 322,
progress: 46,
status: "single",
},
{
firstName: "Hayden",
lastName: "Ritchie",
age: 35,
visits: 208,
progress: 79,
status: "relationship",
},
{
firstName: "Destany",
lastName: "Boehm",
age: 37,
visits: 752,
progress: 97,
status: "relationship",
},
{
firstName: "Kale",
lastName: "Johnston",
age: 36,
visits: 378,
progress: 13,
status: "complicated",
},
{
firstName: "Maybell",
lastName: "Brown",
age: 16,
visits: 783,
progress: 76,
status: "complicated",
},
{
firstName: "Emelia",
lastName: "Cronin",
age: 30,
visits: 655,
progress: 96,
status: "complicated",
},
{
firstName: "Kali",
lastName: "Marvin",
age: 18,
visits: 926,
progress: 57,
status: "complicated",
},
{
firstName: "Khalid",
lastName: "Robel",
age: 34,
visits: 671,
progress: 100,
status: "complicated",
},
{
firstName: "Zena",
lastName: "Hilll",
age: 34,
visits: 934,
progress: 18,
status: "single",
},
{
firstName: "Hiram",
lastName: "Koss",
age: 12,
visits: 757,
progress: 44,
status: "relationship",
},
];