Last active
January 11, 2024 06:54
-
-
Save srsandy/033aeb3d3f5b0cba3553fe65b6c0de09 to your computer and use it in GitHub Desktop.
React Table Server side Pagination and Filtering
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Could you pls create a codesandbox for the same