DEV Community

Cover image for How to build your own reusable table component
Daniel Anthony juwon
Daniel Anthony juwon

Posted on • Edited on

How to build your own reusable table component

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>
Enter fullscreen mode Exit fullscreen mode

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}
/>
Enter fullscreen mode Exit fullscreen mode

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'
    },
 ]
Enter fullscreen mode Exit fullscreen mode

or, another set of data

 const userData = [
    {
      id: 23123,
      name: 'Jude abaga',
      email: 'jude.abaga@abaga.com'
      date: 1237682923189813,
      status: 'pending'
    },
     {
      id: 23128,
      name: 'Dev abaga',
      email: 'devabaga@abaga.com'
      date: 111237682923189813,
      status: 'verified'
    },
 ]
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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

Object.keys(headers).map((header, index))
Enter fullscreen mode Exit fullscreen mode

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

Remember my

<AppTable headers={[]} data={data} />
Enter fullscreen mode Exit fullscreen mode

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

Top comments (5)

Collapse
 
agustinlavalla profile image
AgustinLaValla

Great soluciΓ³n. Thanks

Collapse
 
dansmog profile image
Daniel Anthony juwon

I'm glad you liked it.

Collapse
 
wayder_loyola_a7464df4930 profile image
Wayder Loyola • Edited

Great solution. Thanks!!!

Collapse
 
aguud profile image
Agus Pranyoto

thanks

Collapse
 
rajkumarwishtreetraining profile image
wishtree-rpatel

thanks for this solution, I want to know if i want to add any specific style to any field then how should i do it.
e.g: for status i want to change text color to any specific color.