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

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

<ExpandedWrapper>
  <Item label="ColumnName">{plainValue}</Item>
  <Item label="ColumnName">
    <span>children</span>
  </Item>
</ExpandedWrapper>

¿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.

import { createContext } from 'react'
const ExpandedComponentContext = createContext()

const ExpandedComponentProvider = ({ children, ...rest }) => {
  return (
    <ExpandedComponentContext.Provider value={{ ...rest }}>
      {children}
    </ExpandedComponentContext.Provider>
  )
}

export { ExpandedComponentProvider, ExpandedComponentContext }
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:

step1

Repositorio

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!