diff --git a/components/Blocks/DataTable.tsx b/components/Blocks/DataTable.tsx index 3be79e8b..49bcf6c3 100644 --- a/components/Blocks/DataTable.tsx +++ b/components/Blocks/DataTable.tsx @@ -11,7 +11,8 @@ import { import { Card, Group, Table, Text } from "@mantine/core" import { IconChevronDown, IconChevronUp } from "@tabler/icons-react" -import { useVirtual } from "react-virtual" +import { useVirtual } from "@tanstack/react-virtual" + import { useDebouncedState } from "@mantine/hooks" // outside for reference @@ -33,7 +34,6 @@ export default function DataTable({ //we need a reference to the scrolling element for logic down below const tableContainerRef = useRef(null) - const [scrollY, setScrollY] = useDebouncedState(0, 100) const table = useReactTable({ data: data ?? emptyArray, // So it doesn't break when data is undefined because of reference @@ -49,53 +49,53 @@ export default function DataTable({ const { rows } = table.getRowModel() - //V irtualizing is optional, but might be necessary if we are going to potentially have hundreds or thousands of rows const rowVirtualizer = useVirtual({ - parentRef: tableContainerRef, size: rows.length, - overscan: 10, + parentRef: tableContainerRef, }) - const { virtualItems: virtualRows, totalSize } = rowVirtualizer - const paddingTop = virtualRows.length > 0 ? virtualRows?.[0]?.start || 0 : 0 + + const items = rowVirtualizer.virtualItems + const paddingTop = items.length > 0 ? items[0].start : 0 const paddingBottom = - virtualRows.length > 0 - ? totalSize - (virtualRows?.[virtualRows.length - 1]?.end || 0) + items.length > 0 + ? rowVirtualizer.totalSize - items[items.length - 1].end : 0 //called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table - useEffect(() => { - if (!loadMore || loading) return - - const bottomOfTable = - tableContainerRef.current?.getBoundingClientRect().bottom - - const distanceFromBottom = window.innerHeight - bottomOfTable - - console.log({ distanceFromBottom }) - - if (Math.abs(distanceFromBottom) < 300) { - console.log("fetching more") - loadMore() - } - }, [loadMore, loading, scrollY]) + const fetchMoreOnBottomReached = useCallback( + (containerRefElement?: HTMLDivElement | null) => { + if (containerRefElement) { + const { scrollHeight, scrollTop, clientHeight } = containerRefElement + //once the user has scrolled within 300px of the bottom of the table, fetch more data if there is any + if ( + scrollHeight - scrollTop - clientHeight < 300 && + !loading && + loadMore + ) { + loadMore() + } + } + }, + [loadMore, loading] + ) + //a check on mount and after a fetch to see if the table is already scrolled to the bottom and immediately needs to fetch more data useEffect(() => { - window.addEventListener("scroll", () => { - setScrollY(window.scrollY) - }) - return () => { - window.removeEventListener("scroll", () => { - setScrollY(window.scrollY) - }) - } - }, [setScrollY]) + fetchMoreOnBottomReached(tableContainerRef.current) + }, [fetchMoreOnBottomReached]) return ( -
+
{ + fetchMoreOnBottomReached(e.currentTarget) + }} + > @@ -151,11 +151,12 @@ export default function DataTable({ )} - {virtualRows.map((virtualRow) => { + {items.map((virtualRow) => { const row = rows[virtualRow.index] return ( onRowClicked(row.original) : undefined } @@ -197,13 +198,30 @@ export default function DataTable({ )}