Skip to content

Commit 7abe9b4

Browse files
authored
Merge 37e02c4 into 57d2092
2 parents 57d2092 + 37e02c4 commit 7abe9b4

File tree

4 files changed

+56
-36
lines changed

4 files changed

+56
-36
lines changed

src/components/PaginatedTable/PaginatedTable.tsx

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,27 @@ export const PaginatedTable = <T, F>({
6969
const tableRef = React.useRef<HTMLDivElement>(null);
7070

7171
const activeChunks = useScrollBasedChunks({
72-
containerRef: parentRef ?? tableRef,
72+
parentRef,
73+
tableRef,
7374
totalItems: foundEntities,
74-
itemHeight: rowHeight,
75+
rowHeight,
7576
chunkSize: limit,
7677
});
7778

78-
const handleDataFetched = React.useCallback((total: number, found: number) => {
79-
setTotalEntities(total);
80-
setFoundEntities(found);
81-
setIsInitialLoad(false);
82-
}, []);
79+
const handleDataFetched = React.useCallback(
80+
(total: number, found: number) => {
81+
if (total !== totalEntities) {
82+
setTotalEntities(total);
83+
}
84+
85+
if (found !== foundEntities) {
86+
setFoundEntities(found);
87+
}
88+
89+
setIsInitialLoad(false);
90+
},
91+
[foundEntities, totalEntities],
92+
);
8393

8494
// reset table on filters change
8595
React.useLayoutEffect(() => {
@@ -122,7 +132,7 @@ export const PaginatedTable = <T, F>({
122132
getRowClassName={getRowClassName}
123133
renderErrorMessage={renderErrorMessage}
124134
onDataFetched={handleDataFetched}
125-
isActive={activeChunks.includes(value)}
135+
isActive={activeChunks[value]}
126136
/>
127137
));
128138
};

src/components/PaginatedTable/TableChunk.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {ResponseError} from '../Errors/ResponseError';
88

99
import {EmptyTableRow, LoadingTableRow, TableRow} from './TableRow';
1010
import type {Column, FetchData, GetRowClassName, SortParams} from './types';
11+
import {typedMemo} from './utils';
1112

1213
const DEBOUNCE_TIMEOUT = 200;
1314

@@ -29,7 +30,7 @@ interface TableChunkProps<T, F> {
2930
}
3031

3132
// Memoisation prevents chunks rerenders that could cause perfomance issues on big tables
32-
export const TableChunk = <T, F>({
33+
export const TableChunk = typedMemo(function TableChunk<T, F>({
3334
id,
3435
limit,
3536
totalLength,
@@ -43,7 +44,7 @@ export const TableChunk = <T, F>({
4344
renderErrorMessage,
4445
onDataFetched,
4546
isActive,
46-
}: TableChunkProps<T, F>) => {
47+
}: TableChunkProps<T, F>) {
4748
const [isTimeoutActive, setIsTimeoutActive] = React.useState(true);
4849
const [autoRefreshInterval] = useAutoRefreshInterval();
4950

@@ -150,4 +151,4 @@ export const TableChunk = <T, F>({
150151
{renderContent()}
151152
</tbody>
152153
);
153-
};
154+
});
Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,64 @@
11
import React from 'react';
22

3-
import {throttle} from 'lodash';
4-
5-
import {getArray} from '../../utils';
3+
import {isEqual, throttle} from 'lodash';
64

75
interface UseScrollBasedChunksProps {
8-
containerRef: React.RefObject<HTMLElement>;
6+
parentRef?: React.RefObject<HTMLElement>;
7+
tableRef: React.RefObject<HTMLElement>;
98
totalItems: number;
10-
itemHeight: number;
9+
rowHeight: number;
1110
chunkSize: number;
1211
}
1312

1413
const THROTTLE_DELAY = 100;
1514
const CHUNKS_AHEAD_COUNT = 1;
1615

1716
export const useScrollBasedChunks = ({
18-
containerRef,
17+
parentRef,
18+
tableRef,
1919
totalItems,
20-
itemHeight,
20+
rowHeight,
2121
chunkSize,
22-
}: UseScrollBasedChunksProps): number[] => {
23-
const [activeChunks, setActiveChunks] = React.useState<number[]>(
24-
getArray(1 + CHUNKS_AHEAD_COUNT).map((index) => index),
25-
);
22+
}: UseScrollBasedChunksProps): boolean[] => {
23+
const [activeChunks, setActiveChunks] = React.useState<boolean[]>([true, true]);
2624

2725
const calculateActiveChunks = React.useCallback(() => {
28-
const container = containerRef.current;
29-
if (!container) {
26+
const container = parentRef?.current;
27+
const table = tableRef.current;
28+
if (!container || !table) {
3029
return;
3130
}
3231

33-
const {scrollTop, clientHeight} = container;
34-
const visibleStartIndex = Math.floor(scrollTop / itemHeight);
32+
const tableScrollTop = Math.max(container.scrollTop - table.offsetTop, 0);
33+
const visibleStartIndex = Math.floor(Math.max(tableScrollTop, 0) / rowHeight);
3534
const visibleEndIndex = Math.min(
36-
Math.ceil((scrollTop + clientHeight) / itemHeight),
35+
Math.ceil((tableScrollTop + container.clientHeight) / rowHeight),
3736
totalItems - 1,
3837
);
3938

40-
const startChunk = Math.floor(visibleStartIndex / chunkSize);
41-
const endChunk = Math.floor(visibleEndIndex / chunkSize);
42-
43-
const newActiveChunks = getArray(endChunk - startChunk + 1 + CHUNKS_AHEAD_COUNT).map(
44-
(index) => startChunk + index,
39+
const startChunk = Math.max(
40+
Math.floor(visibleStartIndex / chunkSize) - CHUNKS_AHEAD_COUNT,
41+
0,
4542
);
43+
const endChunk = Math.floor(visibleEndIndex / chunkSize) + CHUNKS_AHEAD_COUNT;
4644

47-
setActiveChunks(newActiveChunks);
48-
}, [chunkSize, containerRef, itemHeight, totalItems]);
45+
const newActiveChunks = [];
46+
for (let i = startChunk; i <= endChunk; i++) {
47+
newActiveChunks[i] = true;
48+
}
49+
50+
if (!isEqual(activeChunks, newActiveChunks)) {
51+
setActiveChunks(newActiveChunks);
52+
}
53+
}, [parentRef, tableRef, rowHeight, totalItems, chunkSize, activeChunks]);
4954

5055
const throttledCalculateActiveChunks = React.useMemo(
5156
() => throttle(calculateActiveChunks, THROTTLE_DELAY),
5257
[calculateActiveChunks],
5358
);
5459

5560
React.useEffect(() => {
56-
const container = containerRef.current;
61+
const container = parentRef?.current;
5762
if (!container) {
5863
return undefined;
5964
}
@@ -63,7 +68,7 @@ export const useScrollBasedChunks = ({
6368
container.removeEventListener('scroll', throttledCalculateActiveChunks);
6469
throttledCalculateActiveChunks.cancel();
6570
};
66-
}, [containerRef, throttledCalculateActiveChunks]);
71+
}, [parentRef, throttledCalculateActiveChunks]);
6772

6873
return activeChunks;
6974
};

src/components/PaginatedTable/utils.ts renamed to src/components/PaginatedTable/utils.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import React from 'react';
2+
13
// invoke passed function at most once per animation frame
24
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35
export function rafThrottle<Fn extends (...args: any[]) => any>(fn: Fn) {
@@ -23,3 +25,5 @@ export function rafThrottle<Fn extends (...args: any[]) => any>(fn: Fn) {
2325
export function calculateColumnWidth(newWidth: number, minWidth = 40, maxWidth = Infinity) {
2426
return Math.max(minWidth, Math.min(newWidth, maxWidth));
2527
}
28+
29+
export const typedMemo: <T>(Component: T) => T = React.memo;

0 commit comments

Comments
 (0)