Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@ export function useVirtualizer_unstable(
if (_virtualizerContext.contextIndex !== actualIndexRef.current) {
actualIndexRef.current = _virtualizerContext.contextIndex;
}

const setActualIndex = React.useCallback(
(index: number) => {
actualIndexRef.current = index;
_virtualizerContext.setContextIndex(index);
console.log('Setting index:', index);
},
[_virtualizerContext]
);
Expand Down Expand Up @@ -79,7 +81,7 @@ export function useVirtualizer_unstable(
new Array(virtualizerLength)
);

const populateSizeArrays = () => {
const populateSizeArrays = React.useCallback(() => {
if (!getItemSize) {
// Static sizes, never mind!
return;
Expand Down Expand Up @@ -107,7 +109,7 @@ export function useVirtualizer_unstable(
childProgressiveSizes.current[index - 1] + childSizes.current[index];
}
}
};
}, [getItemSize, numItems, gap, virtualizerContext]);

const [isScrolling, setIsScrolling] = React.useState<boolean>(false);
const [setScrollTimer, clearScrollTimer] = useTimeout();
Expand Down Expand Up @@ -151,10 +153,6 @@ export function useVirtualizer_unstable(
return;
}

/*
We reset the array every time to ensure children are re-rendered
This function should only be called when update is nessecary
*/
childArray.current = new Array(virtualizerLength);
const _actualIndex = Math.max(newIndex, 0);
const end = Math.min(_actualIndex + virtualizerLength, numItems);
Expand Down Expand Up @@ -200,9 +198,7 @@ export function useVirtualizer_unstable(
const batchUpdateNewIndex = React.useCallback(
(index: number) => {
// Local updates
updateChildRows(index);
updateCurrentItemSizes(index);

// State setters
setActualIndex(index);
},
Expand Down Expand Up @@ -574,28 +570,12 @@ export function useVirtualizer_unstable(
if (actualIndex < 0) {
batchUpdateNewIndex(0);
}
initializeSizeArray();
}, []);

/*
* forceUpdate:
* We only want to trigger this when child render or scroll loading changes,
* it will force re-render all children elements
*/
const forceUpdate = React.useReducer(() => ({}), {})[1];
// If the user passes in an updated renderChild function - update current children
React.useEffect(() => {
if (actualIndex >= 0) {
updateChildRows(actualIndex);
forceUpdate();
}
}, [renderChild, isScrolling]);

React.useEffect(() => {
// Ensure we repopulate if getItemSize callback changes
populateSizeArrays();

// We only run this effect on getItemSize change (recalc dynamic sizes)
}, [getItemSize, gap]);
}, [populateSizeArrays]);

// Effect to check flag index on updates
React.useEffect(() => {
Expand All @@ -611,28 +591,13 @@ export function useVirtualizer_unstable(
}
}, [actualIndex, onRenderedFlaggedIndex, virtualizerLength]);

// Ensure we have run through and updated the whole size list array at least once.
initializeSizeArray();

if (
getItemSize &&
(numItems !== childSizes.current.length ||
numItems !== childProgressiveSizes.current.length)
) {
// Child length mismatch, repopulate size arrays.
populateSizeArrays();
}
const isFullyInitialized = hasInitialized.current && actualIndex >= 0;

// Ensure we recalc if virtualizer length changes
const maxCompare = Math.min(virtualizerLength, numItems);
if (
childArray.current.length !== maxCompare &&
actualIndex + childArray.current.length < numItems
) {
// We update child rows prior to every render
if (isFullyInitialized) {
updateChildRows(actualIndex);
}

const isFullyInitialized = hasInitialized.current && actualIndex >= 0;
return {
components: {
before: 'div',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export function useVirtualizerScrollViewDynamic_unstable(
bufferItems: _bufferItems,
bufferSize: _bufferSize,
enableScrollAnchor,
gap = 0,
} = props;

const sizeTrackingArray = React.useRef<number[]>(
Expand Down Expand Up @@ -70,6 +71,7 @@ export function useVirtualizerScrollViewDynamic_unstable(
numItems: props.numItems,
bufferItems: _bufferItems,
bufferSize: _bufferSize,
gap,
});

const _imperativeVirtualizerRef = useMergedRefs(
Expand Down Expand Up @@ -145,7 +147,7 @@ export function useVirtualizerScrollViewDynamic_unstable(
_imperativeVirtualizerRef.current.setFlaggedIndex(index);
scrollToItemDynamic({
index,
itemSizes: sizeTrackingArray,
getItemSize: props.getItemSize ?? getChildSizeAuto,
totalSize,
scrollViewRef: scrollViewRef as React.RefObject<HTMLDivElement>,
axis,
Expand Down
1 change: 1 addition & 0 deletions packages/react-virtualizer/src/hooks/hooks.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type VirtualizerMeasureDynamicProps = {
numItems: number;
getItemSize: (index: number) => number;
direction?: 'vertical' | 'horizontal';
gap?: number;

/**
* Override recommended number of buffer items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,41 @@ export const useDynamicVirtualizerMeasure = <TElement extends HTMLElement>(
bufferItems,
bufferSize,
virtualizerContext,
gap = 0,
} = virtualizerProps;

const [state, setState] = React.useState({
virtualizerLength: 0,
virtualizerBufferItems: 0,
virtualizerBufferSize: 0,
virtualizerBufferItems: bufferItems ?? 0,
virtualizerBufferSize: bufferSize ?? 0,
});

const numItemsRef = React.useRef<number>(numItems);
const containerSizeRef = React.useRef<number>(0);
const scrollPosition = React.useRef<number>(0);
const { virtualizerLength, virtualizerBufferItems, virtualizerBufferSize } =
state;

const { targetDocument } = useFluent();
const container = React.useRef<HTMLElement | null>(null);

const getIndexFromSizeArray = React.useCallback(
(scrollPos: number): number => {
/* This is used on numItems change
* It checks via current render sizes what the current index should be
*/
let sizeTracker = 0;
for (let i = 0; i < numItems; i++) {
sizeTracker += getItemSize(i) + gap;
if (sizeTracker >= scrollPos) {
return i;
}
}
return 0;
},
[getItemSize, numItems]
);

const handleScrollResize = React.useCallback(
(scrollRef: React.MutableRefObject<HTMLElement | null>) => {
const hasReachedEnd =
Expand Down Expand Up @@ -70,21 +90,20 @@ export const useDynamicVirtualizerMeasure = <TElement extends HTMLElement>(
let i = 0;
let length = 0;

const startIndex = virtualizerContext.contextIndex;
const sizeToBeat = containerSizeRef.current + virtualizerBufferSize * 2;
let startIndex = virtualizerContext.contextIndex;
const currentScrollPos =
scrollRef.current.scrollTop ?? scrollPosition.current;
if (numItemsRef.current !== numItems) {
// Our item count has changed, ensure we have an accurate start index
const newIndex =
getIndexFromSizeArray(currentScrollPos) - virtualizerBufferItems;
startIndex = Math.max(newIndex, 0);
}
numItemsRef.current = numItems;

while (indexSizer <= sizeToBeat && i + startIndex < numItems) {
const iItemSize = getItemSize(startIndex + i);
if (
virtualizerContext.childProgressiveSizes.current.length < numItems
) {
/* We are in unknown territory, either an initial render or an update
in virtualizer item length has occurred.
We need to let the new items render first then we can accurately assess.*/
return virtualizerLength - virtualizerBufferSize * 2;
}

const currentScrollPos = scrollPosition.current;
const currentItemPos =
virtualizerContext.childProgressiveSizes.current[startIndex + i] -
iItemSize;
Expand Down Expand Up @@ -118,6 +137,8 @@ export const useDynamicVirtualizerMeasure = <TElement extends HTMLElement>(
const newBufferSize = bufferSize ?? Math.max(defaultItemSize / 2, 1);
const totalLength = length + newBufferItems * 2;

// This will only trigger if dynamic resize causes changes
virtualizerContext.setContextIndex(startIndex);
setState({
virtualizerLength: totalLength,
virtualizerBufferSize: newBufferSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ export type ScrollToItemStaticParams = {
};

export type ScrollToItemDynamicParams = {
// The goto index
index: number;
itemSizes: React.RefObject<number[]>;
getItemSize: (index: number) => number;
totalSize: number;
scrollViewRef: React.RefObject<HTMLDivElement | null>;
axis?: 'horizontal' | 'vertical';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,18 @@ export const scrollToItemDynamic = (
): void => {
const {
index,
itemSizes,
getItemSize,
totalSize,
scrollViewRef,
axis = 'vertical',
reversed = false,
behavior = 'auto',
} = params;
if (!itemSizes.current) {
return;
}

if (itemSizes.current === null || itemSizes.current.length < index) {
// null check - abort
return;
}

let itemDepth = 0;
for (let i = 0; i < index; i++) {
if (i < index) {
itemDepth += itemSizes.current[i];
itemDepth += getItemSize(i);
}
}

Expand Down
Loading
Loading