-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for variable row heights #2384
Changes from 15 commits
6d21d19
2744dde
7e8be3e
b8032c4
725c0b6
8f8124b
0ae00fb
3e46288
e40ea84
35eaefb
770bbc5
ed6df44
8eb2506
5b0125c
6d4f1de
b982ace
4a0712e
b12e269
42ca9ea
2339400
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
import { useMemo } from 'react'; | ||
import type { GroupRow, GroupByDictionary } from '../types'; | ||
import type { GroupRow, GroupByDictionary, RowHeightArgs } from '../types'; | ||
|
||
const RENDER_BACTCH_SIZE = 8; | ||
|
||
interface ViewportRowsArgs<R> { | ||
rawRows: readonly R[]; | ||
rowHeight: number; | ||
rowHeight: number | ((args: RowHeightArgs<R>) => number); | ||
clientHeight: number; | ||
scrollTop: number; | ||
groupBy: readonly string[]; | ||
|
@@ -94,20 +94,84 @@ export function useViewportRows<R>({ | |
} | ||
}, [expandedGroupIds, groupedRows, rawRows]); | ||
|
||
const { totalRowHeight, getRowTop, getRowHeight, findRowIdx } = useMemo(() => { | ||
if (typeof rowHeight === 'number') { | ||
return { | ||
totalRowHeight: rowHeight * rows.length, | ||
getRowTop: (rowIdx: number) => rowIdx * rowHeight, | ||
getRowHeight: () => rowHeight, | ||
findRowIdx: (offset: number) => Math.floor(offset / rowHeight) | ||
}; | ||
} | ||
|
||
let totalRowHeight = 0; | ||
// Calcule the height of all the rows upfront. This can cause performance issues | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not notice any performance issues even on a large grid. Tried editing, colspan and a few other features. This can be slow if |
||
// and we can consider using a similar approach as react-window | ||
// https://github.com/bvaughn/react-window/blob/master/src/VariableSizeList.js#L68 | ||
const rowPositions = rows.map((row: R | GroupRow<R>) => { | ||
const currentRowHeight = isGroupRow(row) | ||
? rowHeight({ type: 'GROUP', row }) | ||
: rowHeight({ type: 'ROW', row }); | ||
const position = { top: totalRowHeight, height: currentRowHeight }; | ||
totalRowHeight += currentRowHeight; | ||
return position; | ||
}); | ||
|
||
const validateRowIdx = (rowIdx: number) => { | ||
if (rowIdx < 0) { | ||
return 0; | ||
} | ||
|
||
if (rowIdx >= rows.length) { | ||
return rows.length - 1; | ||
} | ||
|
||
return rowIdx; | ||
amanmahajan7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}; | ||
|
||
return { | ||
totalRowHeight, | ||
getRowTop: (rowIdx: number) => rowPositions[validateRowIdx(rowIdx)].top, | ||
getRowHeight: (rowIdx: number) => rowPositions[validateRowIdx(rowIdx)].height, | ||
findRowIdx(offset: number) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use binary search on a sorted array. |
||
let start = 0; | ||
let end = rowPositions.length - 1; | ||
while (start <= end) { | ||
const middle = start + Math.floor((end - start) / 2); | ||
const currentOffset = rowPositions[middle].top; | ||
|
||
if (currentOffset === offset) return middle; | ||
|
||
if (currentOffset < offset) { | ||
start = middle + 1; | ||
} else if (currentOffset > offset) { | ||
end = middle - 1; | ||
} | ||
|
||
if (start > end) return end; | ||
} | ||
return 0; | ||
} | ||
}; | ||
}, [isGroupRow, rowHeight, rows]); | ||
|
||
if (!enableVirtualization) { | ||
return { | ||
rowOverscanStartIdx: 0, | ||
rowOverscanEndIdx: rows.length - 1, | ||
rows, | ||
rowsCount, | ||
isGroupRow | ||
totalRowHeight, | ||
isGroupRow, | ||
getRowTop, | ||
getRowHeight, | ||
findRowIdx | ||
}; | ||
} | ||
|
||
const overscanThreshold = 4; | ||
const rowVisibleStartIdx = Math.floor(scrollTop / rowHeight); | ||
const rowVisibleEndIdx = Math.min(rows.length - 1, Math.floor((scrollTop + clientHeight) / rowHeight)); | ||
const rowVisibleStartIdx = findRowIdx(scrollTop); | ||
const rowVisibleEndIdx = Math.min(rows.length - 1, findRowIdx(scrollTop + clientHeight)); | ||
const rowOverscanStartIdx = Math.max(0, Math.floor((rowVisibleStartIdx - overscanThreshold) / RENDER_BACTCH_SIZE) * RENDER_BACTCH_SIZE); | ||
const rowOverscanEndIdx = Math.min(rows.length - 1, Math.ceil((rowVisibleEndIdx + overscanThreshold) / RENDER_BACTCH_SIZE) * RENDER_BACTCH_SIZE); | ||
|
||
|
@@ -116,6 +180,10 @@ export function useViewportRows<R>({ | |
rowOverscanEndIdx, | ||
rows, | ||
rowsCount, | ||
isGroupRow | ||
totalRowHeight, | ||
isGroupRow, | ||
getRowTop, | ||
getRowHeight, | ||
findRowIdx | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,13 +98,13 @@ function createRows(): readonly Row[] { | |
for (let i = 1; i < 10000; i++) { | ||
rows.push({ | ||
id: i, | ||
year: 2015 + faker.random.number(3), | ||
year: 2015 + faker.datatype.number(3), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
country: faker.address.country(), | ||
sport: sports[faker.random.number(sports.length - 1)], | ||
sport: sports[faker.datatype.number(sports.length - 1)], | ||
athlete: faker.name.findName(), | ||
gold: faker.random.number(5), | ||
silver: faker.random.number(5), | ||
bronze: faker.random.number(5) | ||
gold: faker.datatype.number(5), | ||
silver: faker.datatype.number(5), | ||
bronze: faker.datatype.number(5) | ||
}); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change does not impact the performance if
rowHeight
is a number.