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 hidden or 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 hidden or 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 hidden or 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; | |
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
@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.