Skip to content

Commit 5535639

Browse files
authored
feat: use binary search to calculate range (#114)
1 parent 4e08b80 commit 5535639

File tree

4 files changed

+1887
-982
lines changed

4 files changed

+1887
-982
lines changed

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@
5353
"@babel/preset-react": "^7.8.3",
5454
"@rollup/plugin-replace": "^2.3.1",
5555
"@svgr/rollup": "^4.3.0",
56-
"@testing-library/react": "^9.4.1",
56+
"@testing-library/jest-dom": "^5.11.10",
57+
"@testing-library/react": "^11.2.6",
5758
"babel-core": "7.0.0-bridge.0",
5859
"babel-eslint": "9.x",
5960
"babel-jest": "^24.9.0",
@@ -75,10 +76,11 @@
7576
"eslint-plugin-react-hooks": "1.5.0",
7677
"eslint-plugin-standard": "^4.0.0",
7778
"is-ci-cli": "^2.0.0",
78-
"jest": "^24.9.0",
79+
"jest": "^26.6.3",
7980
"prettier": "^1.19.1",
80-
"react": "^16.13.0",
81-
"react-dom": "^16.13.0",
81+
"react": "^17.0.2",
82+
"react-dom": "^17.0.2",
83+
"react-test-renderer": "^17.0.2",
8284
"rollup": "^1.32.0",
8385
"rollup-plugin-babel": "^4.3.2",
8486
"rollup-plugin-commonjs": "^10.0.0",

src/index.js

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const defaultKeyExtractor = index => index
99
export function useVirtual({
1010
size = 0,
1111
estimateSize = defaultEstimateSize,
12-
overscan = 0,
12+
overscan = 1,
1313
paddingStart = 0,
1414
paddingEnd = 0,
1515
parentRef,
@@ -82,6 +82,9 @@ export function useVirtual({
8282

8383
useIsomorphicLayoutEffect(() => {
8484
if (!element) {
85+
setRange({ start: 0, end: 0 })
86+
latestRef.current.scrollOffset = undefined
87+
8588
return
8689
}
8790

@@ -239,26 +242,43 @@ export function useVirtual({
239242
}
240243
}
241244

245+
const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
246+
while (low <= high) {
247+
let middle = ((low + high) / 2) | 0
248+
let currentValue = getCurrentValue(middle)
249+
250+
if (currentValue < value) {
251+
low = middle + 1
252+
} else if (currentValue > value) {
253+
high = middle - 1
254+
} else {
255+
return middle
256+
}
257+
}
258+
259+
if (low > 0) {
260+
return low - 1
261+
} else {
262+
return 0
263+
}
264+
}
265+
242266
function calculateRange(
243267
{ overscan, measurements, outerSize, scrollOffset },
244268
prevRange
245269
) {
246-
const total = measurements.length
247-
let start = total - 1
248-
while (start > 0 && measurements[start].end >= scrollOffset) {
249-
start -= 1
250-
}
251-
let end = 0
252-
while (
253-
end < total - 1 &&
254-
measurements[end].start <= scrollOffset + outerSize
255-
) {
256-
end += 1
270+
const size = measurements.length - 1
271+
const getOffset = index => measurements[index].start
272+
273+
let start = findNearestBinarySearch(0, size, getOffset, scrollOffset)
274+
let end = start
275+
276+
while (end < size && measurements[end].end < scrollOffset + outerSize) {
277+
end++
257278
}
258279

259-
// Always add at least one overscan item, so focus will work
260280
start = Math.max(start - overscan, 0)
261-
end = Math.min(end + overscan, total - 1)
281+
end = Math.min(end + overscan, size)
262282

263283
if (!prevRange || prevRange.start !== start || prevRange.end !== end) {
264284
return { start, end }

0 commit comments

Comments
 (0)