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
Then in our terminal/CMD we have to install datatable package.
npm install react-data-table-component
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
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>
);
}
Our react project will look like this: