virtual icon indicating copy to clipboard operation
virtual copied to clipboard

Infinite scroll and virtualization lag

Open pinapoluMahesh opened this issue 1 year ago • 2 comments

Describe the bug

Iam using Shadcn ui tables which is built on top of the tanstack tables, i need a infinite scroll which should be smooth -initially it was smooth (befor infinite scroll) until i add infinite scroll for pagination, there it is getting lag at the time of the calling for the next page it is getting lag and in case of virtualization- i didn't get why it is not virtualized i followed everything according to the examples given it would be really help full if any one help me fix this.

`import React from "react"; import { useDispatch, useSelector } from "react-redux";

import Columns from "./Columns"; import DataTable from "../tables/DataTable"; import { useEffect } from "react"; import { fetchCandidates, getCandidates, } from "../../features/candidates/candidateThunks"; import { useState } from "react";

import { QueryClient, QueryClientProvider, keepPreviousData, useInfiniteQuery, } from "@tanstack/react-query"; import { extractValueFromUrl } from "../../features/common/staticUtils";

function CandidatesListTable() { // useGetCandidates(); // const data = useSelector((state) => state.candidates.data); const dispatch = useDispatch();

const { data, fetchNextPage, hasNextPage, isFetching, isLoading } = useInfiniteQuery({ queryKey: [ "candidates", // sorting, //refetch when sorting changes ], queryFn: async ({pageParam=1}) => { const fetchedData = await fetchCandidates({pageParam}); return fetchedData; }, initialPageParam: 1, getNextPageParam: (lastPage, pages) => { const nextPage = extractValueFromUrl(lastPage.next, "page"); const next=Number(nextPage) console.log(nextPage, "next page infy");

    return next?next:undefined
  },
  refetchOnWindowFocus: false,
  placeholderData: keepPreviousData,
});

// console.log( // data, // fetchNextPage, // hasNextPage, // isFetching, // isLoading, // "check for the infy" // );

return ( <> <DataTable data={data} isFetching={isFetching} isLoading={isLoading} fetchNextPage={fetchNextPage} columns={Columns()} /> </> ); }

export default CandidatesListTable;

import { flexRender, getCoreRowModel, getFilteredRowModel, useReactTable } from "@tanstack/react-table"; import { useEffect } from "react";

import { ScrollArea } from "../ui/scroll-area.jsx"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../ui/table.jsx";

import { useVirtualizer } from "@tanstack/react-virtual"; import { useCallback, useMemo, useRef, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; import useDebounce from "../../hooks/useDebounce.js"; import { cn } from "../../lib/utils.js"; import ViewSideBar from "../virtualTables/ViewSideBar.js"; import DataTableControlsAndFilters from "./DataTableControlsAndFilters.js";

function DataTable({ data, fetchNextPage, isFetching, isLoading, columns }) { const dispatch = useDispatch(); const tableContainerRef = useRef(null); const totalCount = data?.totalCount; const isSiderOpen = useSelector((state) => state.virtualTables.isSiderOpen); const debouncedIsHovered = useDebounce(isSiderOpen, 500);

const [open, setOpen] = useState(false); const [container, setContainer] = useState(null);

//flatten the array of arrays from the useInfiniteQuery hook const flatData = useMemo( () => data?.pages?.flatMap((page) => page.results) ?? [], [data] );

useEffect(() => { console.log(flatData, "flatdata"); }, [flatData]);

const totalDBRowCount = data?.pages?.[0]?.count ?? 0; const totalFetched = flatData.length;

//called on scroll and possibly on mount to fetch more data as the user scrolls and reaches bottom of table const fetchMoreOnBottomReached = useCallback( (containerRefElement) => { if (containerRefElement) { const { scrollHeight, scrollTop, clientHeight } = containerRefElement; //once the user has scrolled within 500px of the bottom of the table, fetch more data if we can if ( scrollHeight - scrollTop - clientHeight < 1500 && !isFetching && totalFetched < totalDBRowCount ) { console.log( scrollHeight - scrollTop - clientHeight, "check for the iop" ); fetchNextPage(); } } }, [fetchNextPage, isFetching, totalFetched, totalDBRowCount] );

useEffect(() => { fetchMoreOnBottomReached(tableContainerRef.current); }, []);

const table = useReactTable({ data: flatData, columns, // manualPagination: true, // onSortingChange: setSorting, // onColumnFiltersChange: setColumnFilters, getCoreRowModel: getCoreRowModel(), // getPaginationRowModel: getPaginationRowModel(), // getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), // manualSorting: true, debugTable: true, // onPaginationChange:(e)=>{ // console.log("onPaginationChange",e()) // } // onColumnVisibilityChange: setColumnVisibility, // // onRowSelectionChange: setRowSelection, // state: { // sorting, // columnFilters, // columnVisibility, // rowSelection, // }, });

const { rows } = table.getRowModel();

const virtualizer = useVirtualizer({ count: rows.length, estimateSize: () => 33, //estimate row height for accurate scrollbar dragging getScrollElement: () => tableContainerRef.current, //measure dynamic row height, except in firefox because it measures table border height incorrectly measureElement: typeof window !== "undefined" && navigator.userAgent.indexOf("Firefox") === -1 ? (element) => element?.getBoundingClientRect().height : undefined, overscan: 5, });

console.log(virtualizer.getVirtualItems().length,'length')

return ( <div ref={setContainer} className=" w-full h-full"> <DataTableControlsAndFilters table={table} open={open} setOpen={setOpen} />

  <div
    className={cn(" h-[calc(100vh_-158px)] relative w-full flex flex-row")}
  >
    {" "}
    {open && <ViewSideBar />}

    <ScrollArea
      handleScroll={fetchMoreOnBottomReached}
      // ref={tableContainerRef}
      className={cn(
        `relative  overflow-auto`,
        `w-full`

        // `h-[${virtualizer.getTotalSize()}px]`
      )}
    >
      <div className="h-full w-full" ref={tableContainerRef}>
        <Table style={{ display: "grid" }} className="h-full">
          <TableHeader
            style={{
              display: "grid",
              position: "sticky",
              top: 0,
              zIndex: 1,
            }}
            className="sticky top-0 bg-white z-10"
          >
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow
                style={{ display: "flex", width: "100%" }}
                key={headerGroup.id}
              >
                {headerGroup.headers.map((header) => {
                  return (
                    <TableHead
                      style={{
                        display: "flex",
                        width: header.getSize(),
                      }}
                      key={header.id}
                    >
                      {header.isPlaceholder
                        ? null
                        : flexRender(
                            header.column.columnDef.header,
                            header.getContext()
                          )}
                    </TableHead>
                  );
                })}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody
            style={{
              display: "grid",
              height: `${virtualizer.getTotalSize()}px`, //tells scrollbar how big the table is
              position: "relative", //needed for absolute positioning of rows
            }}
            onScroll={(e) => console.log(e, "scrolllingf")}
          >
            {virtualizer.getVirtualItems()?.length > 0 ? (
              <>
                {virtualizer.getVirtualItems()?.map((virtualRow, index) => {
                  const row = rows[virtualRow.index];
                  const loader = virtualRow.index > rows?.length - 1;
                  return (
                    <TableRow
                      data-index={virtualRow.index} //needed for dynamic row height measurement
                      ref={(node) => virtualizer.measureElement(node)} //measure dynamic row height
                      key={row.id}
                      style={{
                        display: "flex",
                        position: "absolute",
                        transform: `translateY(${virtualRow.start}px)`, //this should always be a `style` as it changes on scroll
                        width: "100%",
                      }}
                      // key={row?.id}
                      // style={{
                      //   // height: `${virtualRow.size}px`,
                      //   transform: `translateY(${
                      //     virtualRow.start - index * virtualRow.size
                      //   }px)`,
                      // }}
                      data-state={row?.getIsSelected() && "selected"}
                    >
                      {row?.getVisibleCells().map((cell) => (
                        <TableCell
                          key={cell.id}
                          style={{
                            display: "flex",
                            width: cell.column.getSize(),
                          }}
                        >
                          {flexRender(
                            cell.column.columnDef.cell,
                            cell.getContext()
                          )}
                        </TableCell>
                      ))}
                    </TableRow>
                  );
                })}

                {/* <Loader2
              ref={ref}
              className="react-table my-4 h-8 w-8 animate-spin"
            /> */}
              </>
            ) : (
              <TableRow>
                <TableCell
                  colSpan={columns.length}
                  className="h-24 text-center"
                >
                  No results.
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </Table>
      </div>
    </ScrollArea>
  </div>
  {/* <DataTableFooter table={table} /> */}
</div>

); }

export default DataTable;

`

thank you

Your minimal, reproducible example

vs code

Steps to reproduce

in infinite scroll at the time of api call there has been a lag

Expected behavior

the scroll should be smooth

How often does this bug happen?

None

Screenshots or Videos

No response

Platform

linux

tanstack-virtual version

v3.5.0

TypeScript version

No response

Additional context

No response

Terms & Code of Conduct

  • [X] I agree to follow this project's Code of Conduct
  • [X] I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

pinapoluMahesh avatar May 16 '24 07:05 pinapoluMahesh

sorry for any mistakes as this is my first time posting an issue in the git hub

pinapoluMahesh avatar May 16 '24 07:05 pinapoluMahesh

create a codesandbox with minimal reproducible problem

slidenerd avatar Feb 07 '25 06:02 slidenerd