ReactJS Datatable
Samuel S

Samuel S @samseptiano

About: Software craftmanship who loves turn caffeine into codes :)

Location:
Jakarta, Indonesia
Joined:
Feb 14, 2023

ReactJS Datatable

Publish Date: Apr 23
1 0

In web applications—especially reporting or monitoring applications—we often need to display a large amount of data from an API. To make data loading faster, we typically design our APIs to support pagination.

In classic JavaScript _frameworks like _jQuery, we are familiar with using DataTables to display paginated data tables. But how do we use DataTables in ReactJS?

First, we create react application by executing in our terminal/CMD

npm create-react-app react-demo-datatable
Enter fullscreen mode Exit fullscreen mode

Then in our terminal/CMD we have to install datatable package.

npm install react-data-table-component
Enter fullscreen mode Exit fullscreen mode

Don't forget to install lodash.debounce package for our search data table. lodash.debounce is a utility function from the Lodash library that delays a function’s execution until after a specified amount of time has passed since it was last called. i will prevent Too many API calls (e.g. every user type) to Maximalize performance issue.

npm install lodash.debounce
Enter fullscreen mode Exit fullscreen mode

Then let's adjust our App.js to look like this:

import React, { useState, useEffect } from "react";
import DataTable from "react-data-table-component";
import debounce from "lodash.debounce";

// Dummy local dataset
const localData = [
  {
    NO_RESI: "PLMAA16157522113",
    RECEIVER_NAME: "John Doe",
    RECEIVER_DIVISION: "IT",
    CREATED_DATE: "2025-04-11",
    STATUS_NAME: "Complete",
    STATUS: "002",
  },
  {
    NO_RESI: "PLMAA16157522112",
    RECEIVER_NAME: "Jane Doe",
    RECEIVER_DIVISION: "Finance",
    CREATED_DATE: "2025-04-10",
    STATUS_NAME: "On Progress",
    STATUS: "001",
  },
  // Add more dummy items here
];

const statusOptions = [
  { key: "001", status: "On Progress" },
  { key: "002", status: "Complete" },
];

const columns = [
  { name: "No Resi", selector: (row) => row.NO_RESI, sortable: true },
  { name: "Receiver", selector: (row) => row.RECEIVER_NAME, sortable: true },
  { name: "Receiver Division", selector: (row) => row.RECEIVER_DIVISION, sortable: true },
  { name: "Created Date", selector: (row) => row.CREATED_DATE, sortable: true },
  { name: "Status", selector: (row) => row.STATUS_NAME, sortable: true },
  {
    name: "Action",
    cell: (row) => (
      <button className="bg-blue-500 text-black px-3 py-1 rounded hover:bg-blue-600">
        Detail
      </button>
    ),
  },
];

const customStyles = {
  headCells: {
    style: {
      backgroundColor: "#919492",
      color: "#333",
      fontWeight: "bold",
      fontSize: "14px",
    },
  },
};

export default function App() {
  const [data, setData] = useState([]);
  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState("");
  const [loading, setLoading] = useState(false);

  const [totalRows, setTotalRows] = useState(0);
  const [perPage, setPerPage] = useState(10);
  const [currentPage, setCurrentPage] = useState(1);

  const filterLocalData = (page, size, searchText, statusKey) => {
    setLoading(true);

    let filtered = [...localData];

    if (searchText) {
      filtered = filtered.filter(
        (item) =>
          item.NO_RESI.toLowerCase().includes(searchText.toLowerCase()) ||
          item.RECEIVER_NAME.toLowerCase().includes(searchText.toLowerCase())
      );
    }

    if (statusKey) {
      filtered = filtered.filter((item) => item.STATUS === statusKey);
    }

    const start = (page - 1) * size;
    const paginated = filtered.slice(start, start + size);

    setData(paginated);
    setTotalRows(filtered.length);
    setLoading(false);
  };

  useEffect(() => {
    filterLocalData(currentPage, perPage, search, statusFilter);
  }, [search, statusFilter, perPage, currentPage]);

  const handlePageChange = (page) => {
    setCurrentPage(page);
  };

  const handlePerRowsChange = (newPerPage, page) => {
    setPerPage(newPerPage);
    setCurrentPage(page);
  };

  const debouncedSearch = debounce((val) => {
    setSearch(val);
  }, 500);

  return (
    <div className="w-full p-4">
      <div className="flex justify-between items-center mb-4 gap-4">
        <select
          className="p-2 border rounded"
          value={statusFilter}
          onChange={(e) => setStatusFilter(e.target.value)}
        >
          <option value="">All Status</option>
          {statusOptions.map((opt) => (
            <option key={opt.key} value={opt.key}>
              {opt.status}
            </option>
          ))}
        </select>

        <input
          type="text"
          placeholder="Search..."
          className="p-2 border rounded w-full max-w-md"
          onChange={(e) => debouncedSearch(e.target.value)}
        />
      </div>

      <DataTable
        columns={columns}
        data={data}
        progressPending={loading}
        pagination
        paginationServer
        paginationTotalRows={totalRows}
        onChangePage={handlePageChange}
        onChangeRowsPerPage={handlePerRowsChange}
        customStyles={customStyles}
      />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Our react project will look like this:

Demo App

Comments 0 total

    Add comment