reactjs - Hvordan håndtere en til mange-relasjon i TanStack Table (React-Table V8)
Jeg prøver for øyeblikket Tanstack Table, som er et flott bibliotek!
Det jeg prøver å gjøre er å lage en tabell som ser slik ut:
Mine data kommer fra et API med denne typen:
type Accounting = {
category: string;
total: number; // Sum of all expenses
expenses: {
name: string;
value: number;
}[];
};
Her er hva jeg har så langt:
const columns = React.useMemo(
() => [
columnHelper.accessor("category", {
header: "Category",
id: "category",
cell: (info) => {
return (
<>
{info.row.getCanExpand() && (
<button
{...{
onClick: info.row.getToggleExpandedHandler(),
style: { cursor: "pointer" },
className: "mr-2",
}}
>
{info.row.getIsExpanded() ? (
<Chevron direction="down" />
) : (
<Chevron direction="right" />
)}
</button>
)}
{info.getValue()}
</>
);
},
}),
columnHelper.accessor("expenses", {
header: undefined,
id: "expense-name",
cell: (info) => {
// FIXME : this returns a table of objects, I want one row per expense
return info.getValue();
},
}),
columnHelper.accessor("expenses", {
aggregationFn: "sum",
id: "expense-value",
header: "Expense",
cell: (info) => {
// FIXME : this returns a table of objects, I want one row per expense
return info.getValue();
},
}),
],
[]
);
const grouping = React.useMemo(() => ["category"], []);
const table = useReactTable({
data,
columns,
state: {
grouping,
expanded,
},
getExpandedRowModel: getExpandedRowModel(),
getGroupedRowModel: getGroupedRowModel(),
getCoreRowModel: getCoreRowModel(),
onExpandedChange: setExpanded,
autoResetExpanded: false,
});
Problemet her er at jeg har et en-til-mange-forhold mellom én kategori og flere utgifter for denne kategorien.
Koden ovenfor fungerer ikke fordi tanstack-tabellen prøver å gjengi en liste med objekter (en liste over utgifter).
Jeg har ikke funnet ut hvordan Tanstack Table kan håndtere dette? Bør jeg overstyre en slags render-metode? Er Tanstack Table det rette valget for denne typen data?
Med respekt.
Svar #1
Du kan hente mye fra React Table-utvidelseseeksempelet.
Den kritiske delen du mangler er getSubRows-funksjonen på tabellen. I stedet for å rendere de enkelte utgiftene inne i cell til foreldrekategorien, ønsker vi å opprette en ny rad i tabellen for hver utgift.
Våre to kolonner er en tittel og et tall. For et toppnivå Accounting-objekt er det category og total. For en individuell utgift er det name og value. Siden dette er forskjellige egenskaper, må vi gjøre noe kartlegging.
La oss starte veldig enkelt og definere de to kolonnene for toppnivåobjektene:
const columns = React.useMemo(
() => [
columnHelper.accessor("category", {
header: "Category",
id: "category"
}),
columnHelper.accessor("total", {
header: "Expense",
id: "expense-value"
})
],
[]
);
La oss nå legge til utvidelsesfunksjonaliteten. (Du trenger ikke grupperingsfunksjonaliteten.)
Vi vil lagre expanded-tilstanden i komponenten og sende den til tabellen, og synkronisere endringer gjennom onExpandedChange-alternativet.
Vi vil legge til et nytt getSubRows-alternativ til tabellen din. Dette er en funksjon som tar det overordnede Accounting-objektet og returnerer et array av underordnede Accounting-objekter. Som forklart tidligere, må vi gi noen egenskaper nye navn for å få grensesnittene til å samsvare. Vår columns-konfig forventer et objekt med category og total. Jeg satte et tomt array for expenses her fordi de underordnede radene ikke har egne barn.
const [expanded, setExpanded] = React.useState<ExpandedState>({});
const table = useReactTable({
data,
columns,
state: {
expanded
},
getExpandedRowModel: getExpandedRowModel(),
getCoreRowModel: getCoreRowModel(),
onExpandedChange: setExpanded,
getSubRows: (originalRow) =>
originalRow.expenses.map((expense) => ({
category: expense.name,
total: expense.value,
expenses: []
}))
});
For kolonnene dine, den eneste endringen jeg gjorde fra den forrige er å vise en utvid/sammentrekke-knapp på parent-radene (som du allerede hadde i forsøket ditt).
const columns = React.useMemo(
() => [
columnHelper.accessor("category", {
header: "Category",
id: "category",
cell: (info) => {
return (
<>
{info.row.getCanExpand() && (
<button onClick={info.row.getToggleExpandedHandler()}>
{info.row.getIsExpanded() ? "-" : "+"}
</button>
)}
{info.getValue()}
</>
);
}
}),
columnHelper.accessor("total", {
header: "Expense",
id: "expense-value"
})
],
[]
);
Nå har vi fullstendig funksjonell radutvidelse. Det er ikke vakkert, men jeg overlater det til deg å legge til stil.
CodeSandbox-demo


