diff --git a/packages/grid/_modules_/grid/hooks/features/virtualization/useGridVirtualColumns.ts b/packages/grid/_modules_/grid/hooks/features/virtualization/useGridVirtualColumns.ts index dd6bd9bee049e..241982e01ca0e 100644 --- a/packages/grid/_modules_/grid/hooks/features/virtualization/useGridVirtualColumns.ts +++ b/packages/grid/_modules_/grid/hooks/features/virtualization/useGridVirtualColumns.ts @@ -13,7 +13,6 @@ import { useGridApiMethod } from '../../root/useGridApiMethod'; import { useGridApiEventHandler } from '../../root/useGridApiEventHandler'; import { gridColumnsMetaSelector, - visibleGridColumnsLengthSelector, visibleGridColumnsSelector, } from '../columns/gridColumnsSelector'; import { useGridSelector } from '../core/useGridSelector'; @@ -27,6 +26,28 @@ type UseVirtualColumnsReturnType = [ UpdateRenderedColsFnType, ]; +// Uses binary search to avoid looping through all possible positions +function getIdxFromScroll( + offset: number, + positions: number[], + sliceStart = 0, + sliceEnd = positions.length, +): number { + if (positions.length <= 0) { + return -1; + } + + if (sliceStart >= sliceEnd) { + return sliceStart; + } + + const pivot = sliceStart + Math.floor((sliceEnd - sliceStart) / 2); + const itemOffset = positions[pivot]; + return offset <= itemOffset + ? getIdxFromScroll(offset, positions, sliceStart, pivot) + : getIdxFromScroll(offset, positions, pivot + 1, sliceEnd); +} + export const useGridVirtualColumns = ( options: GridOptions, apiRef: GridApiRef, @@ -37,21 +58,11 @@ export const useGridVirtualColumns = ( const containerPropsRef = React.useRef(null); const lastScrollLeftRef = React.useRef(0); const columnsMeta = useGridSelector(apiRef, gridColumnsMetaSelector); - const visibleColumnCount = useGridSelector(apiRef, visibleGridColumnsLengthSelector); const visibleColumns = useGridSelector(apiRef, visibleGridColumnsSelector); const getColumnIdxFromScroll = React.useCallback( - (left: number) => { - const positions = columnsMeta.positions; - - if (!visibleColumnCount) { - return -1; - } - let colIdx = [...positions].reverse().findIndex((p) => left >= p); - colIdx = positions.length - 1 - colIdx; - return colIdx; - }, - [columnsMeta.positions, visibleColumnCount], + (left: number) => getIdxFromScroll(left, columnsMeta.positions), + [columnsMeta.positions], ); const getColumnFromScroll = React.useCallback(