Unlock the Power of Sortable Tables in React

Creating the Table Markup

We’ll start by creating a React project with Create React App and setting up the development server. Next, we’ll create the table markup, splitting it into different component files for better organization. We’ll have a Table component as the parent, holding the TableHead and TableBody components.


// Table.js
import React from 'eact';
import TableHead from './TableHead';
import TableBody from './TableBody';

const Table = () => {
  return (
    <table>
      <TableHead />
      <TableBody />
    </table>
  );
};

export default Table;

Fetching and Rendering Table Data

Usually, we fetch table data from an API or backend server asynchronously. For this tutorial, we’ll generate some mock data from Mockaroo and store it in a JSON file. We’ll then import the data and store it in the state, passing it to the TableBody component via props.


// data.json
[
  { id: 1, name: 'John Doe', age: 25 },
  { id: 2, name: 'Jane Doe', age: 30 },
  //...
]

// Table.js
import React, { useState, useEffect } from 'eact';
import data from './data.json';

const Table = () => {
  const [tableData, setTableData] = useState(data);

  return (
    <table>
      <TableHead />
      <TableBody data={tableData} />
    </table>
  );
};

Sorting the Table Data

To sort the table data, we’ll use the JavaScript sort() function, which knows how to collate and order items. We’ll also use the localeCompare() function to handle different data types, including strings, numbers, and dates.


const sortByColumn = (data, column, order) => {
  return data.sort((a, b) => {
    if (order === 'asc') {
      return a[column].localeCompare(b[column]);
    } else {
      return b[column].localeCompare(a[column]);
    }
  });
};

Handling the onClick Event and Sorting Data

When we click a table header, we’ll keep track of the sort order and column using the useState Hook. We’ll then define the logic to switch the order on every header click, updating the table data accordingly.


const TableHead = () => {
  const [sortOrder, setSortOrder] = useState('asc');
  const [sortedColumn, setSortedColumn] = useState(null);

  const handleClick = (column) => {
    if (sortedColumn === column) {
      setSortOrder(sortOrder === 'asc'? 'desc' : 'asc');
    } else {
      setSortOrder('asc');
      setSortedColumn(column);
    }
    // Update table data with new sort order
  };

  return (
    <thead>
      <tr>
        {columns.map((column) => (
          <th key={column} onClick={() => handleClick(column)}>
            {column}
          </th>
        ))}
      </tr>
    </thead>
  );
};

Making the Table Reusable

To make the table reusable, we’ll extract the sorting logic into a custom Hook called useSortableTable. This will enable us to reuse the sorting functionality in different table components.


const useSortableTable = (data, columns) => {
  const [sortOrder, setSortOrder] = useState('asc');
  const [sortedColumn, setSortedColumn] = useState(null);

  const sortedData = sortByColumn(data, sortedColumn, sortOrder);

  const handleHeaderClick = (column) => {
    // Update sort order and sorted column
  };

  return { sortedData, handleHeaderClick };
};

Enabling or Disabling Sorting for Specific Columns

We’ll add a sortable key to the columns items and specify a Boolean value to allow or disallow sorting for any column.


const columns = [
  { id: 'name', label: 'Name', sortable: true },
  { id: 'age', label: 'Age', sortable: false },
  //...
];

Displaying Icons to Indicate Sorting Direction

We’ll dynamically add class names to the table header element to display arrow icons indicating the sorting direction.


<th className={`sortable ${sortedColumn === column? (sortOrder === 'asc'? 'asc' : 'desc') : ''}`} key={column} onClick={() => handleClick(column)}>
  {column}
</th>

Implementing Editable Table Cells

To implement editable table cells, we’ll use the native input element, rendering it in place of a table cell when clicked. We’ll then handle the state updates as typical in React.


const TableCell = ({ value, onChange }) => {
  const [editing, setEditing] = useState(false);

  const handleEdit = () => {
    setEditing(true);
  };

  const handleSave = (newValue) => {
    onChange(newValue);
    setEditing(false);
  };

  return (
    <td>
      {editing? (
        <input type="text" value={value} onChange={(e) => handleSave(e.target.value)} />
      ) : (
        <span onClick={handleEdit}>{value}</span>
      )}
    </td>
  );
};

Optimizing Performance for Large Datasets

Finally, we’ll cover some strategies for optimizing performance when rendering large datasets in React, including:

  • Pagination
  • Virtualization
  • Memoization
  • Server-side sorting
  • Lazy loading

By following this tutorial, you’ll learn how to create a sortable table from scratch using React, reuse the table logic, and optimize performance for large datasets.

Leave a Reply