debounce table loader

This commit is contained in:
jeffvli
2025-11-01 01:29:05 -07:00
parent 5f0309d12b
commit 0e9f9f2fe1
@@ -2,6 +2,7 @@
import { useMergedRef } from '@mantine/hooks'; import { useMergedRef } from '@mantine/hooks';
import clsx from 'clsx'; import clsx from 'clsx';
import debounce from 'lodash/debounce';
import { AnimatePresence } from 'motion/react'; import { AnimatePresence } from 'motion/react';
import { useOverlayScrollbars } from 'overlayscrollbars-react'; import { useOverlayScrollbars } from 'overlayscrollbars-react';
import React, { import React, {
@@ -14,7 +15,7 @@ import React, {
useRef, useRef,
useState, useState,
} from 'react'; } from 'react';
import { type CellComponentProps, Grid, type GridProps } from 'react-window-v2'; import { type CellComponentProps, Grid } from 'react-window-v2';
import styles from './item-table-list.module.css'; import styles from './item-table-list.module.css';
@@ -46,7 +47,7 @@ interface VirtualizedTableGridProps {
internalState: ItemListStateActions; internalState: ItemListStateActions;
itemType: LibraryItem; itemType: LibraryItem;
mergedRowRef: React.Ref<HTMLDivElement>; mergedRowRef: React.Ref<HTMLDivElement>;
onCellsRendered?: GridProps<TableItemProps>['onCellsRendered']; onRangeChanged?: ItemTableListProps['onRangeChanged'];
onRowClick?: (item: any, event: React.MouseEvent<HTMLDivElement>) => void; onRowClick?: (item: any, event: React.MouseEvent<HTMLDivElement>) => void;
parsedColumns: ReturnType<typeof parseTableColumns>; parsedColumns: ReturnType<typeof parseTableColumns>;
pinnedLeftColumnCount: number; pinnedLeftColumnCount: number;
@@ -80,7 +81,7 @@ const VirtualizedTableGrid = React.memo(
internalState, internalState,
itemType, itemType,
mergedRowRef, mergedRowRef,
onCellsRendered, onRangeChanged,
onRowClick, onRowClick,
parsedColumns, parsedColumns,
pinnedLeftColumnCount, pinnedLeftColumnCount,
@@ -200,6 +201,23 @@ const VirtualizedTableGrid = React.memo(
[pinnedLeftColumnCount, pinnedRowCount, CellComponent], [pinnedLeftColumnCount, pinnedRowCount, CellComponent],
); );
const debouncedOnCellsRendered = useMemo(() => {
return debounce(
(items: {
columnStartIndex: number;
columnStopIndex: number;
rowStartIndex: number;
rowStopIndex: number;
}) => {
onRangeChanged?.({
startIndex: items.rowStartIndex,
stopIndex: items.rowStopIndex,
});
},
45,
);
}, [onRangeChanged]);
return ( return (
<div className={styles.itemTableContainer}> <div className={styles.itemTableContainer}>
<div <div
@@ -294,7 +312,7 @@ const VirtualizedTableGrid = React.memo(
columnWidth={(index) => { columnWidth={(index) => {
return columnWidth(index + pinnedLeftColumnCount); return columnWidth(index + pinnedLeftColumnCount);
}} }}
onCellsRendered={onCellsRendered} onCellsRendered={debouncedOnCellsRendered}
rowCount={totalRowCount} rowCount={totalRowCount}
rowHeight={(index, cellProps) => { rowHeight={(index, cellProps) => {
return getRowHeight(index + pinnedRowCount, cellProps); return getRowHeight(index + pinnedRowCount, cellProps);
@@ -419,14 +437,8 @@ interface ItemTableListProps {
type: 'index' | 'offset'; type: 'index' | 'offset';
}; };
itemType: LibraryItem; itemType: LibraryItem;
onCellsRendered?: GridProps<TableItemProps>['onCellsRendered']; onRangeChanged?: (range: { startIndex: number; stopIndex: number }) => void;
onEndReached?: (index: number, internalState: ItemListStateActions) => void;
onRangeChanged?: (
range: { endIndex: number; startIndex: number },
internalState: ItemListStateActions,
) => void;
onScrollEnd?: (offset: number, internalState: ItemListStateActions) => void; onScrollEnd?: (offset: number, internalState: ItemListStateActions) => void;
onStartReached?: (index: number, internalState: ItemListStateActions) => void;
ref?: Ref<ItemListHandle>; ref?: Ref<ItemListHandle>;
rowHeight?: ((index: number, cellProps: TableItemProps) => number) | number; rowHeight?: ((index: number, cellProps: TableItemProps) => number) | number;
size?: 'compact' | 'default' | 'large'; size?: 'compact' | 'default' | 'large';
@@ -448,11 +460,8 @@ export const ItemTableList = ({
headerHeight = 40, headerHeight = 40,
initialTop, initialTop,
itemType, itemType,
onCellsRendered,
onEndReached,
onRangeChanged, onRangeChanged,
onScrollEnd, onScrollEnd,
onStartReached,
ref, ref,
rowHeight, rowHeight,
size = 'default', size = 'default',
@@ -950,10 +959,10 @@ export const ItemTableList = ({
if (lastIndex !== -1 && currentIndex !== -1) { if (lastIndex !== -1 && currentIndex !== -1) {
// Create range selection // Create range selection
const startIndex = Math.min(lastIndex, currentIndex); const startIndex = Math.min(lastIndex, currentIndex);
const endIndex = Math.max(lastIndex, currentIndex); const stopIndex = Math.max(lastIndex, currentIndex);
const rangeItems: ItemListItem[] = []; const rangeItems: ItemListItem[] = [];
for (let i = startIndex; i <= endIndex; i++) { for (let i = startIndex; i <= stopIndex; i++) {
const rangeItem = data[i]; const rangeItem = data[i];
if ( if (
rangeItem && rangeItem &&
@@ -1015,59 +1024,6 @@ export const ItemTableList = ({
[data, enableSelection, internalState, itemType], [data, enableSelection, internalState, itemType],
); );
const handleOnCellsRendered = useCallback(
(cells: {
columnStartIndex: number;
columnStopIndex: number;
rowStartIndex: number;
rowStopIndex: number;
}) => {
onRangeChanged?.(
{
endIndex: cells.rowStopIndex,
startIndex: cells.rowStartIndex,
},
internalState,
);
if (onStartReached || onEndReached) {
if (cells.rowStartIndex === 0) {
onStartReached?.(0, handleRef.current ?? (undefined as any));
}
if (cells.rowStopIndex + 10 >= totalItemCount) {
onEndReached?.(totalItemCount, handleRef.current ?? (undefined as any));
}
}
if (onCellsRendered) {
return ({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) => {
return onCellsRendered!(
{
columnStartIndex: columnStartIndex + pinnedLeftColumnCount,
columnStopIndex: columnStopIndex + pinnedLeftColumnCount,
rowStartIndex: rowStartIndex + pinnedRowCount,
rowStopIndex: rowStopIndex + pinnedRowCount,
},
cells,
);
};
}
return undefined;
},
[
onCellsRendered,
onEndReached,
onRangeChanged,
onStartReached,
pinnedLeftColumnCount,
pinnedRowCount,
totalItemCount,
internalState,
],
);
const isInitialScrollPositionSet = useRef<boolean>(false); const isInitialScrollPositionSet = useRef<boolean>(false);
useEffect(() => { useEffect(() => {
@@ -1134,7 +1090,7 @@ export const ItemTableList = ({
internalState={internalState} internalState={internalState}
itemType={itemType} itemType={itemType}
mergedRowRef={mergedRowRef} mergedRowRef={mergedRowRef}
onCellsRendered={handleOnCellsRendered} onRangeChanged={onRangeChanged}
onRowClick={handleRowClick} onRowClick={handleRowClick}
parsedColumns={parsedColumns} parsedColumns={parsedColumns}
pinnedLeftColumnCount={pinnedLeftColumnCount} pinnedLeftColumnCount={pinnedLeftColumnCount}