Infinite scroll and virtualization lag
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 35/100
- Tipo de issue
- Bug
- Clareza
- Precisa de esclarecimento
- Status de atividade
- Estagnada
- Stack de tecnologia
- react, typescript
- Domínio
- frontend, performance
Direção de pesquisa
Comece com o código fornecido de CandidatesListTable e DataTable, concentrando-se na configuração de @tanstack/react-virtual, em tableContainerRef e no caminho handleScroll de ScrollArea. Reproduza a chamada da API de infinite scroll durante a rolagem e, em seguida, determine se o elemento de rolagem e o comportamento de virtualização correspondem aos exemplos. Está concluído quando a rolagem é suave durante as buscas de páginas e a virtualização funciona.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
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 (
<>
</>
);
}
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
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
- I agree to follow this project's Code of Conduct
- 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.
- Linguagem predominante
- TypeScript
- Estrelas
- 7.1k
- Forks
- 472
- Merge médio
- 1d 1h
- PRs com merge (30d)
- 11
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de TanStack/virtual
-
measureElement caches 0 size for nodes that aren't attached yet (Vue: rows stack at start 0 and the list scrolls away on mount)Talvez já em andamento @webn00b assumiu há 13 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
Mantenedores costumam responder em até 1 dia
-
anchorTo: 'end' loses the end when the scroll element shrinksTalvez já em andamento @langleyd assumiu há 2 dias. Aberta
Dificuldade 3/5 1-2 dias Facilidade para iniciantes 68/100
Mantenedores costumam responder em até 1 dia
-
`scrollToIndex(last, { align: 'end' })` stays short of the end after a measured row grows (virtual-core ≥ 3.17.0)Talvez já em andamento @minwookshin assumiu há 10 dias. Aberta
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 55/100
TanStack/virtual#1290 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
virtual-core: desktop Safari drops the prepend anchor write when history lands during the top rubber-band bounceTalvez já em andamento Um pull request vinculado a esta issue está aberto ou já foi mesclado. Aberta
Dificuldade 5/5 Mais de uma semana Facilidade para iniciantes 38/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 4/5 3-5 dias Facilidade para iniciantes 62/100
Mantenedores costumam responder em até 1 dia
Todas as issues de TanStack/virtual
Issues semelhantes
-
Add: YRF Music NepalAbertastreams:add
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 62/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
walletbeat/walletbeat#1558 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
hawk-digital-environments/HAWKI#438 ·
Mantenedores costumam responder em até 1 dia
-
Bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
GiganticMinecraft/seichi-portal-frontend#1165 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 1/5 1-3 horas Facilidade para iniciantes 84/100
Mantenedores costumam responder em até 1 dia