React Tanstack Table
React Tanstack Table o antes llamado React Table es una biblioteca para poder crear Tablas en un frontend de React. De hecho React Tanstack Table es una biblioteca Headless, lo que significa que no trae estilos ni todos los componentes hechos sino que te da las funcionalidades por partes para que las importes a medida que te hagan falta.
Creación del Proyecto con React Tanstack Table
npm create vite
npm install @tanstack/react-table
Con el proyecto creado, ahora creemos una componente que muestre una tabla sencilla en src/components/SimpleTable.jsx
Datos de ejemplo
Para los datos de ejemplo, podemos usar mockaro
Creacion de Primer Tabla
import {
flexRender,
useReactTable,
getCoreRowModel,
} from "@tanstack/react-table";
import data from "../MOCK_DATA.json";
function SimpleTable() {
const columns = [
{
header: "ID",
accessorKey: "id",
footer: "ID",
},
{
header: "First Name",
accessorKey: "name",
footer: "First Name",
},
{
header: "Last Name",
accessorKey: "lastname",
footer: "Last Name",
},
{
header: "Email",
accessorKey: "email",
footer: "Email",
},
{
header: "Date of Birth",
accessorKey: "dateOfBirth",
footer: "Date of Birth",
},
{
header: "Country",
accessorKey: "country",
footer: "Country",
},
];
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<div>
<table>
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id}>
{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>
<tfoot>
{table.getFooterGroups().map((footerGroup) => (
<tr key={footerGroup.id}>
{footerGroup.headers.map((header) => (
<th key={header.id}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</th>
))}
</tr>
))}
</tfoot>
</table>
</div>
);
}
export default SimpleTable;
Añadir los estilos
body {
padding: 7rem;
}
table {
border-collapse: collapse;
border-spacing: 0;
width: 100%;
border: 1px solid #ddd;
}
thead, tfoot {
background-color: #333;
color: #fff;
}
th,
td {
text-align: left;
padding: 16px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
Procesando celdas
Para procesar una celda podemos usar
import dayjs from 'dayjs'
{
header: "Date of Birth",
accessorKey: "dateOfBirth",
footer: "Date of Birth",
cell: info => dayjs(info.value).format('DD/MM/YYYY')
},
Procesando Filas
ahora si en una sola columna queremos colocar datos que vienen de la fila tambien podemos accederlo:
quitamos la columna name y lastname y lo reemplazamos por:
{
header: "FullName",
accessorFn: row => `${row.name} ${row.lastname}`,
footer: "FullName",
},
Segundo Header Group
{
header: "Fullname",
columns: [
{
header: "First Name",
accessorKey: "name",
footer: "First Name",
},
{
header: "Last Name",
accessorKey: "lastname",
footer: "Last Name",
},
],
},
Y Luego para que no se muestren los headers por defecto podemos colocar una condicional:
<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>
Paginacion
import {
getPaginationRowModel,
} from "@tanstack/react-table";
const table = useReactTable({
getPaginationRowModel: getPaginationRowModel(),
});
<div>
<button onClick={() => table.setPageIndex(0)}>First Page</button>
<button
disabled={!table.getCanPreviousPage()}
onClick={() => table.previousPage()}
>
Previous Page
</button>
<button
disabled={!table.getCanNextPage()}
onClick={() => table.nextPage()}
>
Next Page
</button>
<button onClick={() => table.setPageIndex(table.getPageCount() - 1)}>
Last Page
</button>
</div>
Ordenamiento de Filas
const [sorting, setSorting] = useState([]); const table = useReactTable({ state: { sorting, }, onSortingChange: setSorting });
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
onClick={header.column.getToggleSortingHandler()}
>
{header.isPlaceholder ? null : (
<div>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{
{asc: '⬆️', desc: '⬇️'}[header.column.getIsSorted() ?? null]
}
</div>
)}
</th>
))}
</tr>
))}
</thead>
Filtering
const [filtering, setFiltering] = useState("");
const table = useReactTable({ state: { globalFilter: filtering, }, onGlobalFilterChange: setFiltering, });
<input
type="text"
value={filtering}
onChange={(e) => setFiltering(e.target.value)}
/>
Creacion de componente Reutilizable
El crear una tabla reutilizable no es necesario que la creemos una y otra vez.