Skip to content

Commit

Permalink
fix(Table): fix virtualized table scrolling exception (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonguo authored Sep 7, 2022
1 parent cf1682d commit a0c1696
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 23 deletions.
12 changes: 2 additions & 10 deletions docs/md/UpdateData.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,13 @@ const mockData = (length, start) => {
};

const App = () => {
const [dataNum, setDataNum] = React.useState(9000);
const [dataNum, setDataNum] = React.useState(1000);
const data = React.useMemo(() => mockData(dataNum, 0), [dataNum]);
console.log('currentDataLen', data.length, dataNum);

return (
<div>
<Table
width={300}
height={400}
data={data}
virtualized={true}
shouldUpdateScroll={false}
showHeader={false}
bordered
>
<Table width={300} height={400} data={data} virtualized shouldUpdateScroll={false} bordered>
<Column width={200} align="center" flexGrow={1}>
<HeaderCell>ID</HeaderCell>
<Cell dataKey="index" />
Expand Down
9 changes: 6 additions & 3 deletions src/Scrollbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,15 @@ const Scrollbar = React.forwardRef((props: ScrollbarProps, ref) => {
}
: {};

const getSafeValue = (value = 0) => {
return Math.min(Math.max(value, 0), max);
};

if (typeof forceDelta === 'undefined') {
scrollOffset.current += delta;
scrollOffset.current = Math.max(scrollOffset.current, 0);
scrollOffset.current = Math.min(scrollOffset.current, max);
scrollOffset.current = getSafeValue(scrollOffset.current);
} else {
scrollOffset.current = forceDelta || 0;
scrollOffset.current = getSafeValue(forceDelta);
}

if (vertical) {
Expand Down
1 change: 1 addition & 0 deletions src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ const Table = React.forwardRef((props: TableProps, ref) => {
fillHeight,
children,
expandedRowKeys,
showHeader,
onTableScroll: debounce((coords: { x?: number; y?: number }) => onScrollTo(coords), 100),
onTableResizeChange: handleTableResizeChange
});
Expand Down
34 changes: 24 additions & 10 deletions src/utils/useTableDimension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { RowDataType, RowKeyType, ElementOffset } from '../@types/common';

interface TableDimensionProps {
data?: readonly RowDataType[];
rowHeight?: number | ((rowData: RowDataType) => number);
rowHeight: number | ((rowData: RowDataType) => number);
height: number;
minHeight: number;
tableRef?: React.RefObject<HTMLDivElement>;
Expand All @@ -25,6 +25,7 @@ interface TableDimensionProps {
fillHeight?: boolean;
children?: React.ReactNode;
expandedRowKeys?: RowKeyType[];
showHeader?: boolean;
onTableScroll?: (coord: { x?: number; y?: number }) => void;
onTableResizeChange?: (
prevSize: number,
Expand Down Expand Up @@ -55,6 +56,7 @@ const useTableDimension = (props: TableDimensionProps) => {
fillHeight,
children,
expandedRowKeys,
showHeader,
onTableResizeChange,
onTableScroll
} = props;
Expand Down Expand Up @@ -82,8 +84,9 @@ const useTableDimension = (props: TableDimensionProps) => {

const calculateTableContextHeight = useCallback(() => {
const prevContentHeight = contentHeight.current;
const table = tableRef?.current;
const table = tableRef?.current as HTMLDivElement;
const rows = table?.querySelectorAll(`.${prefix?.('row')}`) || [];
const virtualized = table?.querySelectorAll('.virtualized')?.length > 0;

const nextContentHeight = rows.length
? (
Expand All @@ -107,6 +110,7 @@ const useTableDimension = (props: TableDimensionProps) => {
}

const height = fillHeight ? tableHeight.current : heightProp;
const tableBodyHeight = showHeader ? height - headerHeight : height;

if (!autoHeight) {
/**
Expand All @@ -122,11 +126,20 @@ const useTableDimension = (props: TableDimensionProps) => {
onTableScroll?.({ y: 0 });
}

// If the value of scrollTop is greater than the scrollable range, the vertical scroll bar is reset.
// When Table is set to virtualized, the logic will be entered every time the wheel event is triggered
// to avoid resetting the scroll bar after scrolling to the bottom, so add the SCROLLBAR_WIDTH value.
if (Math.abs(scrollY.current) + height - headerHeight > nextContentHeight + SCROLLBAR_WIDTH) {
onTableScroll?.({ y: scrollY.current });
const currentScrollTop = Math.abs(scrollY.current);

// When Table is set to virtualized, the logic will be entered every time the wheel event is
// triggered to avoid resetting the scroll bar after scrolling to the bottom, so add the SCROLLBAR_WIDTH value.
const maxScrollTop = nextContentHeight + SCROLLBAR_WIDTH - tableBodyHeight;

// If the top value of the current scroll is greater than the scrollable range,
// keep the vertical scroll bar at the bottom.
if (maxScrollTop > 0 && currentScrollTop > maxScrollTop) {
if (virtualized) {
onTableScroll?.({ y: (data?.length || 0) * getRowHeight() - tableBodyHeight });
} else {
onTableScroll?.({ y: maxScrollTop });
}
}

if (prevContentHeight !== contentHeight.current) {
Expand All @@ -137,9 +150,10 @@ const useTableDimension = (props: TableDimensionProps) => {
prefix,
affixHeader,
headerHeight,
autoHeight,
fillHeight,
heightProp,
autoHeight,
showHeader,
getRowHeight,
data,
onTableScroll,
Expand Down Expand Up @@ -252,12 +266,12 @@ const useTableDimension = (props: TableDimensionProps) => {

useUpdateLayoutEffect(() => {
calculateTableWidth();
calculateTableContextHeight();
calculateTableContentWidth();
calculateTableContextHeight();
}, [
data,
heightProp,
contentHeight,
contentHeight.current,
expandedRowKeys,
children,
calculateTableContextHeight,
Expand Down

0 comments on commit a0c1696

Please sign in to comment.