How I write my reusable Table component in react

Most web applications always have one way or the other to display large data sets on their web page, and the most common one is using tables. Tables are extremely useful to displaying large sets of data, and you can add filtering functionality to it also, not like the filtering is tied to the tables anyways.

So recently after joining klen, one of the things I had to do as a frontend developer was to create reusable components for most of the components on the application. This article is about creating reusable table components, so lets cut the chase.

My Initial table component set up

Before joining Klen, I had a table component that I use mostly for my code project, more like a base structure for the react, then you can update the styles to make it look exactly like whatever the designer designs. My table component structure is like so

<table className="table">
        <thead className="headBg">
          <tr>
            {headers.map(header => {
              return (
                <th scope="col" key={header}>
                  {header}
                </th>
              );
            })}
          </tr>
        </thead>
        <tbody>
          {data.map(datum => {
            return (
              <tr key={datum.id} onClick={() => console.log(datum.id)}>
                <td>#{datum.id}</td>
                <td className="d-flex justify-content-center align-items-center customer--details">
                  <img src={datum.image} alt="" />

                  <span>
                    {datum.firstname} {datum.lastname}
                  </span>
                </td>
                <td>#{datum.transactionId}</td>

                <td>{datum.name}</td>
                <td>N{datum.amount}</td>
                <td className="d-flex justify-content-center align-items-center">{this.renderStatusTag(datum.status)}</td>
                <td>{moment(datum.createdAt).format("DD-MM-YYYY")}</td>
                <td>{moment(datum.createdAt).format("h:mm a")}</td>
              </tr>
            );
          })}
        </tbody>
      </table>

the above code snippet is how I used to write my table component. It basically works this way,

  • Pass an array of string for the header
  • pass an array of object for the table list item

and inside the table component its self, I loop through the two arrays to render their individual data.

and then it's imported like so

<AppTable 
  headers={['header title 1', 'header title 2']}
  data={data}
/>

wherever I want to use.

This worked well at a point, but the component is restricted because of the following

  • That the component knows the kind of data to expect
  • It's hardcoded.
  • Too much copying and pasting to make the table render the exact data for different types of table

All these I have noticed with the current way of writing my table component, but I was too lazy to change it, so after joining klen, I made up my mind to update my table component.

The following things are what I considered while refactoring the component

  • What every data that is being passed, the table should be able to render the table row with its appropriate table data
  • The table must be dynamic

Table data can be dynamic

Whatever data I pass to this table, it should render it.
for instance, I could have any of the following

const earningsData = [
    {
      id: 23123,
      name: 'Jude abaga',
      date: 1237682923189813,
      amount_paid: '4560000'
    },
     {
      id: 23123,
      name: 'Jude Gideon',
      date: 12376829231189813,
      amount_paid: '560000'
    },
 ]

or, another set of data

const userData = [
    {
      id: 23123,
      name: 'Jude abaga',
      email: '[email protected]'
      date: 1237682923189813,
      status: 'pending'
    },
     {
      id: 23128,
      name: 'Dev abaga',
      email: '[email protected]'
      date: 111237682923189813,
      status: 'verified'
    },
 ]

Whatever kind of data I am passing as the data prop, it should be able to render the table row without breaking. so how did I achieve this? below is a code snippet

<tbody>
            {data.map((datum, index) => {
              return (
                <tr key={datum.id}>
                  {Object.keys(headers).map((header, index) => {
                      <td key={index}>
                          <span>{datum[header]}</span>                      
                      </td>

                  })}
                </tr>
              );
            })}
          </tbody>

The single most important line of code in the above snippet is this one below

Object.keys(headers).map((header, index))

Now my table component now has to parts to it, which are

Remember my

<AppTable headers={[]} data={data} />

takes a headers props, so what I did, was to convert the headers prop from an array to an object, this way I can easily map an item in the data array to the headers. So what this does is, it returns the keys in the headers object and maps through it, then look for the individual item in the data object

30