Mostrar datos en tablas es un requisito duradero de las interfaces de usuario. React Table se describe como una biblioteca de tablas «casi sin cabeza» para React. Se centra en brindarle todos los aspectos de los datos en un formato conveniente y le deja a usted el estilo y la creación de componentes. Este enfoque facilita la creación de potentes cuadrículas de datos y su diseño según sea necesario. En este artículo, usaremos el react-table
Biblioteca para crear una tabla con estilo, filtrado, clasificación y paginación.
¿Qué es la tabla de reacciones?
La versión más reciente del tabla de reacciones La biblioteca es parte de TanStack, un proyecto más grande que proporciona componentes de forma independiente del marco. Respectivamente, react-table
puede controlar componentes de tabla para varios marcos: React, Solid, Vue, Svelte y aplicaciones creadas con TypeScript o JavaScript. Nuestros ejemplos se centran en la construcción de una tabla en React.
Para proporcionar datos para la tabla, usaremos un punto final localhost que proporciona datos de criptomonedas, incluida la marca de tiempo, el precio, el volumen y la capitalización de mercado de varias monedas. Por ejemplo, los datos de una fila se verán como el Listado 1.
Listado 1. Una fila de datos de criptomonedas
{ cryptocurrency: 'solana',
timestamp: 1586563521174,
price: 0.9576058280146803,
volume: 92672667.43447028,
marketCap: 7827651.892659198 }
El punto final que estamos usando es localhost:3001/crypto-data.
Para crear un nuevo proyecto, utilice npx create-react-app iw-react-table
. (Estas instrucciones asumen que usted tiene Nodo/NPM instalado.) Entonces tú puedes cd
en lo nuevo /iw-react-table
directorio.
Comenzaremos con una tabla simple para mostrar estos datos, creando un nuevo componente en src/CryptoTable.js
con el contenido del Listado 2.
Listado 2. Una tabla simple construida usando reaccionar-table
import React, { useState, useEffect, useMemo } from 'react';
import { useTable } from 'react-table';
const CryptoTable = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("http://35.188.145.46:3001/crypto-data")
.then((response) => response.json())
.then((data) => {
setData(data);
setLoading(false);
})
.catch((error) => {
console.error('Error fetching data:', error);
setLoading(false);
});
}, []);
// Define columns for the table
const rawColumns = [
{ Header: 'Timestamp', accessor: 'timestamp', },
{ Header: 'Cryptocurrency', accessor: 'cryptocurrency', },
{ Header: 'Price', accessor: 'price', },
{ Header: 'Volume', accessor: 'volume', },
{ Header: 'Market Cap', accessor: 'marketcap',
},
];
const columns = useMemo(() => rawColumns, []);
// Create a table instance
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
});
if (loading) {
return <div>Loading...</div>;
}
return (
<table {...getTableProps()} className="crypto-table">
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map(row => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
);
})}
</tr>
);
})}
</tbody>
</table>
);
};
export default CryptoTable;
Algo de esto es típico de React: creamos dos variables de estado con useState: data
para contener los datos en sí, y loading
para controlar la visualización del texto de carga. Llamamos useEffect
para hacer la llamada de fondo con fetch
.
Luego, creamos las columnas de la tabla. La configuración básica de la columna requiere el «Encabezado» y el «accesor», que son la etiqueta de la columna y la clave que se utiliza para acceder al campo en los objetos de la fila. Después de eso, llamamos al useMemo
gancho en las columnas (obtenga más información sobre useMemo aquí). Memorizar evita volver a ejecutar las llamadas del descriptor de acceso para cada fila. Sin memorizar, React podría percibir que la aplicación había entrado en un bucle infinito al cargar grandes conjuntos de datos.
A continuación creamos la tabla con useTable
gancho, que viene de react-table
. Este gancho acepta el columns
definición y los datos mismos. Con eso, tiene suficiente información para construir una cuadrícula. El useTable
gancho devuelve un objeto con todas las propiedades necesarias para configurar el marcado de la tabla. Estos se desestructuran en los métodos y accesorios que los componen, como getTableProps
y getTableBodyProps
, que luego usamos en el marcado. Esto es bastante sencillo, aunque notarás que en realidad usamos las matrices de filas y columnas en JSX para representar el th
, tr
y td
elementos.
Aquí es donde empezamos a involucrarnos más en la construcción de la tabla real que con una biblioteca más orientada a componentes. Sin embargo, puede ver que no es tan complejo y obtenemos acceso práctico a las partes internas de la mesa. Este control detallado podría resultar muy útil cuando se trata de personalizaciones de casos extremos.
Los resultados de nuestro código actual nos darán una vista como la que se muestra en la Figura 1. (Tenga en cuenta que es un buen momento para comprar algunas criptomonedas BTC).
Figura 1. Una tabla básica construida con React y reaccionar-table.
Ejecute la aplicación
Para utilizar el nuevo componente CryptoTable, puede actualizar su src/App.js
para parecerse al Listado 3.
Listado 3. Usar el componente
import React from 'react';
import './App.css';
import CryptoTable from './CryptoTable1';
function App() {
return (
<div className="App">
<h1>Crypto Data</h1>
<CryptoTable />
</div>
);
}
export default App;
Ejecute la aplicación con: $ /iw-react-table/npm start
. Visite localhost:3000 para comprobar los resultados.
Estilo
Ahora, agreguemos algo de estilo. El CSS moderno facilita pasar del aspecto primitivo de la Figura 1 a algo decente. El Listado 4 muestra algunos estilos de tabla simples.
Listado 4. Estilos de tabla
crypto-table {
width: 100%;
}
.crypto-table th,
.crypto-table td {
border: 1px solid black;
padding: 5px;
}
.crypto-table th {
background-color: #eee;
}
.crypto-table {
border-collapse: collapse;
border: 1px solid #ccc;
font-family: sans-serif;
font-size: 14px;
}
.crypto-table th,
.crypto-table td {
border: 1px solid #ccc;
padding: 10px;
}
.crypto-table th {
background-color: #eee;
text-align: left;
}
.crypto-table td {
text-align: right;
}
.crypto-table tr:nth-child(even) {
background-color: #f9f9f9;
}
.crypto-table tr:hover {
background-color: #ddd;
}
Esto nos dará una apariencia similar a la tabla de la Figura 2.
Figura 2. Una tabla de React básica con algo de estilo.
Clasificación del lado del cliente
Ahora agreguemos la funcionalidad de clasificación que react-table
manejará por nosotros en la memoria. En nuestro caso, en última instancia queremos realizar la clasificación del lado del servidor, pero este ejemplo le permite ver lo fácil que es realizar la clasificación del lado del cliente. Para agregar clasificación del lado del cliente, siga estos pasos:
- Importar
useSort
dereact-table
- Agréguelo a la tabla así:
useTable({ columns, data }, useSortBy);
- Modifique el marcado del encabezado de la tabla como se muestra en el Listado 5.
Listado 5. Encabezado de tabla ordenable
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.render('Header')}
<span>
{column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : ''}
</span>
</th>
))}
</tr>
))}
</thead>
Ahora, cuando haces clic en un encabezado, se ordenará en esa columna y mostrará el ícono apropiado.
Clasificación del lado del servidor
Para el siguiente paso, hagamos que la clasificación utilice la parte posterior. Nuestra API acepta sortBy
y sortOrder
parámetros en la URL, por lo que el primer paso es agregar sortBy
y sortOrder
ganchos estatales. (Recuerde eliminar la clasificación del lado del cliente). Luego, use esas variables en la URL de esta manera.
fetch(`http://localhost:3001/crypto-data?sortBy=${sortBy}&sortOrder=${sortOrder}`)
Además, debemos establecer el sortBy
y sortOrder
como variables dependientes en el useEffect
que recupera los datos. Haga esto agregándolos a la matriz en el segundo argumento para useEffect
.
Ahora, agregue una función para manejar la acción cuando el usuario hace clic en un encabezado, como se muestra en el Listado 6. (Aquí me salté el ícono del encabezado por brevedad).
Listado 6. Controlador de clasificación y clic
const handleSortClick = (column) => {
if (column.sortable) {
// Determine the new sort order
const newSortOrder = sortBy === column.id && sortOrder === 'asc' ? 'desc' : 'asc';
setSortBy(column.id);
setSortOrder(newSortOrder);
}
};
Para manejar el clic, puede agregar el siguiente controlador de eventos al <th>
elemento: onClick={() => handleSortClick(column)}
. Observe que comprobamos column.sortable
que podemos configurar en las columnas cuando las creamos, por ejemplo:
{ Header: 'Timestamp', accessor: 'timestamp', sortBy: 'timestamp', sortable: true }
Ahora, cada vez que hagas clic en el encabezado, la tabla se recargará con la columna apropiada ordenada por el backend.
Filtración
Podemos utilizar un proceso similar para manejar el filtrado. Digamos que queremos filtrar por criptomonedas. Podemos agregar un menú desplegable y aplicarlo a la URL mediante una variable de estado (selectedCrypto
). Ahora el fetch
la llamada se verá así:
fetch(`http://35.188.145.46:3001/crypto-data?sortBy=${sortBy}&sortOrder=${sortOrder}&cryptoCurrency=${selectedCrypto}`)
Recuerda agregar selectedCrypto
a la lista de variables dependientes para useEffect
.
Podemos agregar un menú desplegable como se muestra en el Listado 7.
Listado 7. Menú Cripto
<select value={selectedCrypto} onChange={handleCryptoChange}>
<option value="bitcoin">Bitcoin</option>
<option value="ethereum">Ethereum</option>
<option value="solana">Solana</option>
</select>
Y todo lo que queda es manejar el evento de cambio, como se muestra en el Listado 8.
Listado 8. Manejador de eventos de cambio criptográfico
const handleCryptoChange = (event) => {
setSelectedCrypto(event.target.value);
};
Ahora, cuando se selecciona la moneda, la tabla se volverá a representar con la configurada en la URL.
paginación
La paginación también se puede realizar en el cliente o en el servidor. El proceso de paginación en el servidor es muy similar a ordenar y filtrar, así que veamos un ejemplo del lado del cliente. Terminaremos con algo como lo que se muestra en la Figura 3, con controles para avanzar y retroceder, configurar el tamaño de la página y saltar a una página, junto con una visualización de cuántas páginas existen.
Figura 3. Paginación del lado del cliente con tabla de reacción.
Para lograr esto, necesitamos:
- Importar el
usePagination
gancho. - Utilice el nuevo gancho con la creación de instancias de la tabla y exponga las funciones para controlar la paginación.
El comando de importación para el usePagination
gancho es: import { useTable, usePagination } from 'react-table';
. El Listado 9 muestra el nuevo gancho y las funciones para controlar la paginación.
Listado 9. Creación de tablas con paginación
const {
getTableProps, getTableBodyProps, headerGroups, page, // Get the current page of data
// Add pagination functions and variables
previousPage,
nextPage,
canPreviousPage,
canNextPage,
gotoPage, // Add gotoPage function
pageCount, // Add pageCount variable
pageOptions, // Add pageOptions variable
setPageSize, // Add setPageSize function
prepareRow, state: { pageIndex, pageSize }, // Current page index and page size
} = useTable({
columns,
data,
initialState: { pageIndex: 0, pageSize: 10 }, // Set the initial page index and page size
},
usePagination // Add the usePagination hook
);
Agregue el marcado que utiliza los controles, como se muestra en el Listado 10.
Listado 10. Controles de paginación
<div className="pagination">
<button onClick={() => gotoPage(0)} disabled={pageIndex === 0}> {'<<'} </button>
<button onClick={() => previousPage()} disabled={!canPreviousPage}>{'<'}</button>
<button onClick={() => nextPage()} disabled={!canNextPage}>{'>'}</button>
<button onClick={() => gotoPage(pageCount - 1)} disabled={pageIndex === pageCount - 1}>
{'>>'} </button>
<span> Page{' '} <strong> {pageIndex + 1} of {pageOptions.length} </strong>{' '} </span>
<span> | Go to page:{' '} <input type="number" defaultValue={pageIndex + 1} onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}} />
</span>
<select value={pageSize} onChange={(e) => { setPageSize(Number(e.target.value)); }} >
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
Básicamente, creamos un formulario para interactuar con las funciones de la página como gotoPage
y canNextPage
. Si pruebas esto, notarás que react-table
es capaz de manejar grandes conjuntos de datos con buena capacidad de respuesta.
Conclusión
Este artículo ha demostrado algunas de las características clave en react-table
. Hay mucho más que la biblioteca puede manejar. Por ejemplo, aquí está cómo hacer desplazamiento infinito con mesas virtuales, filas expandibles, y más.
A pesar de react-table
obviamente está bien pensado y es capaz, lo más convincente es lo fácil que hace el renderizado y la creación de eventos; esto significa que casi cualquier cosa que necesites hacer es posible sin profundizar en los aspectos internos de React. No sorprende que esta biblioteca sea tan popular, con más de millones de descargas semanales desde NPM.
Encontrarás el código completo de los ejemplos en el repositorio de este artículo.
Copyright © 2024 IDG Communications, Inc.