Envoltorio móvil RDT con React Context
Una de las cosas complejas que un desarrollador web necesita hacer es mostrar tablas, básicamente porque una tabla necesita ser fácil de usar, me refiero a proporcionar paginación, filtrado, ordenación y todo lo demás para manejar los datos. A veces lograr esto en el escritorio es complejo pero factible, pero en el lado móvil puede ser incluso un poco más complejo, es por eso que ahora voy a compartir mi envoltura de tabla para hacer esta tarea fácil.
Como se lee en el título, una cosa que necesitamos para empezar a construir nuestras tablas es React Data Table Component (RDT) que es un potente paquete que proporciona una buena API para ordenar, paginar, filtrar, estilizar y mucho más.
Ahora bien, si usted has visto a la documentación de RDT, es probable que hayas notado que la configuración para hacer la tabla móvil responsiva ya está integrada, así que ¿cuál es el punto de este post?
Bueno, la opción está ahí, pero cuando necesitas añadir botones de acción para abrir una ventana modal, descargar un archivo, o lo que necesites hacer, es muy probable que tengas que repetir el código varias veces, dependiendo de cuántas tablas necesite tu aplicación.
Con el fin de explicar lo que va a resolver esta envoltura voy a proporcionar un repositorio con todo el código utilizado.
Instalación RDT
- Instala RDT utilizando uno de los siguientes comandos:
npm i react-data-table-component styled-componentsyarn react-data-table-component styled-components
dataprop: un array de objetos donde se contiene toda la información de la tabla.columnsprop: un objeto memorizado donde se definirán las columnas, por ejemplo:
const columns = useMemo(() => [
{
name: 'Column name 1',
id: 'columnId1',
selector: ({ attribute1 }) => attribute1
},
{
name: 'Column name 2',
id: 'columnId2',
selector: ({ attribute2 }) => attribute2
},
{
name: 'actions',
id: 'actions',
cell: ({ attribute3 }) => (
<div>
<span onClick={(attribute3) => {}}Action 1</span>
</div>
),
hide: 'md'
}
// más columnas...
], [])
Añadiendo la propiedad hide: 'md' si la resolución de la ventana es menor que la resolución de escritorio la columna se ocultará automáticamente, eso es fácil pero ahora se necesita una manera de mostrar en el móvil y ahora es donde el ExpandedComponent será útil.
Creación de la envoltura
Tablebásicamente será una envoltura general creada sólo para compartir los estilos en caso de que la aplicación necesite utilizar varias tablas, puedes encontrar más detalles aquí: RDT PatternsExpandedComponentanatomía básica:
<ExpandedWrapper>
<Item label="ColumnName">{plainValue}</Item>
<Item label="ColumnName">
<span>children</span>
</Item>
</ExpandedWrapper>
- ¿Qué son
ExpandedWrappereItem? Ambos son componentes únicos utilizados para mantener la coherencia de los estilos y puedes crear tus propios componentes como quieras:ExpandedWrapperconst ExpandedWrapper = ({ children }) => { return <div className="grid text-sm mr-4">{children}</div> }Itemconst Item = ({ label, children }) => { return ( <div className="flex"> <div className="max-w-max my-2 ml-16 font-semibold"> <span>{label}</span> </div> <div className="max-w-max my-2 ml-4"> <span>{children}</span> </div> </div> ) }
¿Cuál es el problema?
La respuesta es muy sencilla, el Datatable tiene un componente data y esto se comparte automáticamente en el componente expandido, pero si necesita proporcionar funcionalidad a sus botones de acción o enlaces, necesita crear la función para la vista de escritorio en el “componente principal” y la función móvil en el “componente expandido”, así que aquí es dondeReact Context ayudará a evitar la duplicación de código utilizando algunas líneas de código individuales.
ExpandedComponentProvider
import { createContext } from 'react'
const ExpandedComponentContext = createContext()
const ExpandedComponentProvider = ({ children, ...rest }) => {
return (
<ExpandedComponentContext.Provider value={{ ...rest }}>
{children}
</ExpandedComponentContext.Provider>
)
}
export { ExpandedComponentProvider, ExpandedComponentContext }
useExpandedComponent
import { useContext } from 'react'
import { ExpandedComponentContext } from 'contexts/ExpandedComponentProvider'
const useExpandedComponent = () => {
const context = useContext(ExpandedComponentContext)
if (context === undefined) {
throw new Error('useExpandedComponent must be used within a ExpandedComponentProvider')
}
return context
}
export default useExpandedComponent
Ahora puedes envolver tu tabla utilizando ExpandedComponentProvider para compartir todas las funciones o props que quieras y luego en el componente expandido utiliza el hook useExpandedComponent para conseguirlos todos y usarlos como quieras, nota: expandableRows es una bandera que debe controlar cuando utilizar el componente expandido, por ejemplo, utilizando una media query o una función para obtener el ancho de la ventana, por ejemplo:
import { useCallback, useMemo } from 'react'
import { Table } from 'components/Table'
import { ExpandedComponentProvider } from 'contexts/ExpandedComponentProvider'
import ExpandedExampleComponent from 'components/ExpandedExampleComponent'
const Example = () => {
const data = [
{
attribute1: 'attribute1'
},
{
attribute2: 'attribute2'
},
{
attribute3: 'attribute3'
}
]
const handleClick = useCallback(
(url) => () => {
window.open(url, '_blank', 'noopener,noreferrer,resizable')
}, [])
const columns = useMemo(() => [
{
name: 'Column name 1',
id: 'columnId1',
selector: ({ attribute1 }) => attribute1
},
{
name: 'Column name 2',
id: 'columnId2',
selector: ({ attribute2 }) => attribute2
},
{
name: 'Actions',
id: 'actions',
cell: ({ attribute3 }) => (
<span onClick {handleClick(attribute3)}Action 1</span>
),
hide: 'md'
}
// más columnas...
], [])
return (
<ExpandedComponentProvider onClick={handleClick}>
<Table
name="demo"
columns={columns}
data={data || []}
expandableRows
expandableRowsComponent={ExpandedExampleComponent}
// más props...
/>
</ExpandedComponentProvider>
)
}
export default Example
y el ExpandedExampleComponent :
import { Item, ExpandedWrapper } from 'components/Table'
import useExpandedComponent from 'hooks/useExpandedComponent'
const ExpandedExampleComponent = ({ data }) => {
const { onClick } = useExpandedComponent()
const { attribute1, attribute2, attribute3 } = data
return (
<ExpandedWrapper>
<Item label="Column Name 1">{attribute1}</Item>
<Item label="Column Name 2">{attribute2}</Item>
<Item label="Actions">
<span onClick={onClick(attribute3)}Action 1</span>
</Item>
</ExpandedWrapper>
)
}
export default ExpandedExampleComponent
Vista previa:

Reflexiones finales
Como puedes ver puedes crear tablas increíbles usando RDT y en combinación con React Context también puedes añadir una forma fácil de manejarlas sin mucho esfuerzo.
Espero que esta pequeña aportación pueda ayudarte a reducir los tiempos de implementación de tablas, para mi ha sido muy fácil trabajar con ellas evitando repetir código a la vez que ha facilitado su mantenimiento.
¡Feliz codificación!