Skip to content

Instantly share code, notes, and snippets.

@srsandy
Last active January 11, 2024 06:54
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save srsandy/033aeb3d3f5b0cba3553fe65b6c0de09 to your computer and use it in GitHub Desktop.
Save srsandy/033aeb3d3f5b0cba3553fe65b6c0de09 to your computer and use it in GitHub Desktop.
React Table Server side Pagination and Filtering
import "regenerator-runtime/runtime";
import { useState } from "react";
import { useAsyncDebounce } from "react-table";
const ColumnFilter = ({ column }) => {
const { filterValue, setFilter } = column;
const [value, setValue] = useState(filterValue);
const onChange = useAsyncDebounce((value) => {
setFilter(value || undefined);
}, 300);
return (
<span>
<input
className="border-0 h-6 w-full text-black"
placeholder="Search"
value={value || ""}
onChange={(e) => {
setValue(e.target.value);
onChange(e.target.value);
}}
/>
</span>
);
};
export default ColumnFilter;
// TODO: Fix babel -> ReferenceError: regeneratorRuntime is not defined
import "regenerator-runtime/runtime";
import { useState } from "react";
import { useAsyncDebounce } from "react-table";
const GlobalFilter = ({ filter, setFilter }) => {
const [value, setValue] = useState(filter);
const onChange = useAsyncDebounce((value) => {
setFilter(value || undefined);
}, 300);
return (
<span>
Search:{" "}
<input
className="border h-10 mb-5 w-72"
value={value || ""}
onChange={(e) => {
setValue(e.target.value);
onChange(e.target.value);
}}
/>
</span>
);
};
export default GlobalFilter;
// TODO: fix the below key issue
/* eslint-disable react/jsx-key */
import { useState, useEffect, useMemo, useCallback } from "react";
import {
useTable,
usePagination,
useGlobalFilter,
useFilters,
} from "react-table";
import Spinner from "../shared/Spinner";
import GlobalFilter from "./GlobalFilter";
import ColumnFilter from "./ColumnFilter";
import { COLUMNS } from "./columns";
import styles from "./ViewAllStudents.module.css";
const ViewAllStudents = () => {
const PAGE_NO = 0;
const [recordsPerPage, setRecordsPerPage] = useState(50);
const [totalPage, setTotalPages] = useState(1);
const [tableData, setTableData] = useState([]);
const [loading, setLoding] = useState(false);
const columns = useMemo(() => COLUMNS, []);
const defaultColumn = useMemo(
() => ({
Filter: ColumnFilter,
}),
[]
);
const fetchStudentsData = useCallback(
async (pageNo, recordsPerPage, searchText = "", filters) => {
try {
const res = await fetch(
`/api/student?pageNo=${pageNo}&recordsPerPage=${recordsPerPage}&searchText=${searchText}&filters=${JSON.stringify(
filters
)}`
);
const json = await res.json();
setTableData(json?.data?.students || []);
setTotalPages(json?.data?.totalPages || 1);
setLoding(false);
} catch (err) {}
},
[]
);
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
page,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
setPageSize,
setGlobalFilter,
// Get the state from the instance
state: { pageIndex, pageSize, globalFilter, filters },
} = useTable(
{
columns,
data: tableData,
defaultColumn,
manualPagination: true,
manualGlobalFilter: true,
manualFilters: true,
initialState: {
pageIndex: PAGE_NO,
pageSize: recordsPerPage,
},
pageCount: totalPage,
},
useFilters,
useGlobalFilter,
usePagination
);
useEffect(() => {
setLoding(true);
fetchStudentsData(pageIndex + 1, recordsPerPage, globalFilter, filters);
}, [pageIndex, recordsPerPage, globalFilter, fetchStudentsData, filters]);
useEffect(() => {
setRecordsPerPage(pageSize);
gotoPage(0);
}, [pageSize, gotoPage]);
return (
<div>
<GlobalFilter filter={globalFilter} setFilter={setGlobalFilter} />
<div className="p-2">
<button
className="bg-zinc-300 p-1 mx-2"
onClick={() => gotoPage(0)}
disabled={!canPreviousPage}
>
{"<<"}
</button>
<button
className="bg-zinc-300 p-1 mx-2"
onClick={() => previousPage()}
disabled={!canPreviousPage}
>
{"<"}
</button>
<button
className="bg-zinc-300 p-1 mx-2"
onClick={() => nextPage()}
disabled={!canNextPage}
>
{">"}
</button>
<button
className="bg-zinc-300 p-1 mx-2"
onClick={() => gotoPage(pageCount - 1)}
disabled={!canNextPage}
>
{">>"}
</button>
<span>
Page{" "}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>
</span>
<span>
| Go to page:
<input
type="number"
value={pageIndex + 1}
onChange={(e) => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: "100px" }}
/>
</span>
<select
value={pageSize}
onChange={(e) => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map((pageSize) => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</select>
</div>
{loading ? (
<Spinner />
) : (
<div className="max-w-full overflow-x-scroll">
<table className={styles.table} {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th
className={styles.cell}
{...column.getHeaderProps({
style: {
minWidth: column.minWidth,
width: column.width,
},
})}
>
{column.render("Header")}
<div>
{column.canFilter && column.id !== "_id"
? column.render("Filter")
: null}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return (
<td
className={styles.cell}
{...cell.getCellProps({
style: {
minWidth: cell.minWidth,
width: cell.width,
},
})}
>
{cell.render("Cell")}
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
</div>
)}
</div>
);
};
export default ViewAllStudents;
@srsandy
Copy link
Author

srsandy commented Feb 9, 2023

@ShivkumarSalunkhe thank you for reaching out. This code from a project to which I no longer have access. If you can give me codesandbox link. I will try to fix it and help you.

@srsandy
Copy link
Author

srsandy commented Feb 10, 2023

Could you pls create a codesandbox for the same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment