Skip to main content

How To Integrate @tanstack/react-table with react-hook-form

react-hook-form과 @tanstack/react-table을 이용해서 테이블을 만들어보았습니다.

import * as React from "react";

import {
RowData,
createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";
import { MenuItem, Select } from "@mui/material";
import { Control, Controller, useForm } from "react-hook-form";
import Selection from "./Selection";
import useTables from "./useTables";

type Person = {
firstName: string;
lastName: string;
age: number;
visits: number;
status: string;
progress: number;
};

declare module "@tanstack/react-table" {
interface TableMeta<TData> {
control: Control;
}
}

const defaultData: Person[] = [
{
firstName: "tanner",
lastName: "linsley",
age: 24,
visits: 100,
status: "In Relationship",
progress: 50,
},
{
firstName: "tandy",
lastName: "miller",
age: 40,
visits: 40,
status: "Single",
progress: 80,
},
{
firstName: "joe",
lastName: "dirte",
age: 45,
visits: 20,
status: "Complicated",
progress: 10,
},
];

const STATUS = [
{ name: "a", id: "1", value: "Complicated" },
{ name: "b", id: "2", value: "Single" },
{ name: "c", id: "3", value: "In Relationship" },
];

const AGE = [
{ name: "40", id: "1", value: 40 },
{ name: "24", id: "2", value: 7 },
{ name: "45", id: "3", value: 19 },
{ name: "45", id: "3", value: 39 },
{ name: "45", id: "3", value: 28 },
{ name: "45", id: "3", value: 22 },
{ name: "45", id: "3", value: 9 },
{ name: "45", id: "3", value: 24 },
{ name: "45", id: "3", value: 18 },
{ name: "45", id: "3", value: 30 },
{ name: "45", id: "3", value: 31 },
];

const columnHelper = createColumnHelper<Person>();

function App() {
const [defaultValues, setDefaultValues] = React.useState({});
const { control, watch, setValue } = useForm({});

const columns = [
columnHelper.accessor("firstName", {
header: "firstName",
cell: (info) => info.getValue(),
// footer: (info) => info.column.id,
}),
columnHelper.accessor((row) => row.lastName, {
id: "lastName",
cell: (info) => <i>{info.getValue()}</i>,
header: () => <span>Last Name</span>,
// footer: (info) => info.column.id,
}),
columnHelper.accessor("visits", {
header: () => <span>Visits</span>,
// footer: (info) => info.column.id,
}),
columnHelper.accessor("progress", {
header: "Profile Progress",
}),
columnHelper.accessor("status", {
header: "Status",
cell: (table) => {
return (
<Controller
control={table.table.options.meta?.control}
defaultValue={table.getValue()}
name={`userInfo.${table.row.id}.status`}
render={({ field }) => {
return (
<Select {...field} defaultValue={table.getValue()}>
{STATUS.map((el) => {
return (
<MenuItem key={el.id} value={el.value}>
{el.name}
</MenuItem>
);
})}
</Select>
);
}}
/>
);
},
}),
columnHelper.accessor("age", {
header: () => "Age",
cell: (table) => {
return (
<Controller
control={control}
defaultValue={table.getValue()}
name={`userInfo.${table.row.id}.age`}
render={({ field }) => {
return (
<Select {...field}>
{AGE.map((el) => {
return (
<MenuItem key={el.id} value={el.value}>
{el.value}
</MenuItem>
);
})}
</Select>
);
}}
/>
);
},
}),
];

const {
table: tables,
globalFilter,
setGlobalFilter,
rowSelection,
} = useTables();

const datas = React.useMemo(
() =>
tables.getSelectedRowModel().rows.map((el) => {
return el.original;
}),
[rowSelection, tables]
);

const table = useReactTable<any>({
data: datas,
columns,
getCoreRowModel: getCoreRowModel(),
meta: {
control,
},
});

React.useEffect(() => {
const defaultValue = { userInfo: {} };
tables.getSelectedRowModel().rows.forEach((el) => {
setValue(`userInfo.${el.id}.age`, el.original.age);
setValue(`userInfo.${el.id}.status`, el.original.status);
setValue(`userInfo.${el.id}.firstName`, el.original.firstName);
});
setDefaultValues(defaultValue);
}, [tables, rowSelection]);

return (
<div className="p-2">
<Selection
table={tables}
globalFilter={globalFilter}
setGlobalFilter={setGlobalFilter}
/>
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id}>
{row.getVisibleCells().map((cell) => (
<td key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
<div className="h-4" />
</div>
);
}

export default App;