Multiple react-table instances on same page

Viewed 2320

I'm using react-table in a NextJS project and I'm wondering how I can have more than one table on the same page. Been digging around but haven't found anything about it.

I have an instance on the page already and I'm not sure if I'm over thinking it but I was thinking I could just make a tableInstance2 but then, how would I tell the second table JSX to use that second batch of data?

  const tableInstance = useTable({
    columns: COLUMNS,
    data: tableData
  },
  useSortBy);

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow
  } = tableInstance;

Here is my current table markup:

{tableData.length > 0 && 
  <div className={styles.tableSpace}>
    <table {...getTableProps()} className={styles.table}>
      <thead className={styles.thead}>
        {headerGroups.map((headerGroup) => (
          <tr {...headerGroup.getHeaderGroupProps()} className={styles.tr}>
            {headerGroup.headers.map((column) => (
              <th {...column.getHeaderProps(column.getSortByToggleProps())} className={styles.th}>
                {column.render('Header')}
                  {column.Header !== 'Description' && 
                    <span>
                      {column.isSorted ? (column.isSortedDesc ? <FontAwesomeIcon className={styles.faCaretDown} icon={faCaretDown} /> : <FontAwesomeIcon className={styles.faCaretUp} icon={faCaretUp} />) : <FontAwesomeIcon className={styles.faArrowsAltV} icon={faArrowsAltV} />}
                    </span>
                  }
              </th>
            ))}
          </tr>
        ))}
      </thead>

      <tbody {...getTableBodyProps} className={styles.tbody}>
        {rows.map(row => {
          prepareRow(row)
          return (
            <tr {...row.getRowProps()} className={styles.tr}>
              {row.cells.map((cell) => {
                return (
                  <td {...cell.getCellProps()} className={styles.td}>
                    {cell.render('Cell')}
                  </td>
                )
              })}
            </tr>
          )
        })}
      </tbody>
    </table>
  </div>
}

Is having more than 1 on the same page (in the same file) possible? Would appreciate any tips. Thanks very much!

3 Answers

React table helps you an make your own table component - which you did. You just need move your table to it's own file and generalize the columns.

Below is an example of a generalized and reusable table - you can extend your table component like any of the official examples to enable things like paging or sorting. React-table also wants you to memoize the columns (and data) so I cast the columns to memo in the reusable component so you don't have to on every page with a table.

table.js

export const Table = ({ columns, data, noDataComponent, ...rest }) => {
  const tableColumns = useMemo(() => columns, [columns]);
  const { getTableBodyProps, getTableProps, headerGroups, prepareRow, rows } = useTable({ columns: tableColumns, data });

  if (!rows.length) {
    if (noDataComponent) return noDataComponent;
    return <>No data</>;
  }

  return (
    <table {...getTableProps()} {...rest}>
      <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) => {
                const { className, style } = cell.column;
                return (
                  <td {...cell.getCellProps({ className, style })}>
                    {cell.render('Cell')}
                  </td>
                );
              })}
            </tr>
          );
        })}
      </tbody>
    </table>
  );
};

Multiple tables on the same page using the reusable component. Each table can have it's own data, number of columns, etc. - they are independent from each other.

const columns = [
  {
    Header: 'Test ID',
    accessor: 'test.id', // use dot notation for nested data
    style: { width: '75px' },
  },
  {
    Header: 'Name',
    accessor: 'name',
  },
  {
    accessor: 'id',
    style: { width: '75px' },
    Cell: ({ cell }) => {
      const { 'test.id': testId, name, id }= cell.row.values; // access other data from the row
      console.log(cell);
      return <>Custom component</> // return any ReactNode like a delete button, icons, transform the value, etc.
    },
  },
];

const TablePage = () => (
  <>
   <Table data={tableData} columns={columns} />
   <Table data={tableData2} columns={columns2} />
  </>
)

If there is reasonable reuse between the two tables you should consider implementing your own Table component which wraps the useTable hook.

However if you really want to include both tables in the same component you can rename destructured variables as described in this MDN Example. This allows you to differentiate the variables for both tables.

See example (rename the variables to something suitable to your application's context):

const {
    getTableProps: getFirstTableProps,
    getTableBodyProps: getFirstTableBodyProps,
    headerGroups: firstGeaderGroups,
    rows: firstRows,
    prepareRow: firstPrepareRow
} = tableInstance;

I really appreciate the replies on this. They collectively steered my thinking & helped me to find the solution that worked best for my situation. Seems to be different ways to handle this but because my table markup had some differences & one had sort functionality and the other didn't...I chose not to paint myself into a corner and just have 1 reusable table component.

I figured for future maintainability & more flexibility when adding new tables, I chose to have a component for each table and just included those two tables as components, on the page.

The data needed for both tables is still retrieved on the page level and then the data is passed into the respective components. The different columns are defined in each component and so are the different table instances.

Thanks again, very much to those you gave me options.

Related