Skip to content
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

Virtualizer: Optimize IO usage and export useMeasureList #32375

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3f0c7e3
Export helper function for useMeasureList
Mitch-At-Work Aug 23, 2024
ab70756
Add change file
Mitch-At-Work Aug 23, 2024
b6fbcd2
Update API
Mitch-At-Work Aug 23, 2024
c0765a6
Optimize virtualizer
Mitch-At-Work Aug 23, 2024
1aff223
Truncate width/height arrays
Mitch-At-Work Aug 23, 2024
6ec8d78
Lint
Mitch-At-Work Aug 23, 2024
d000103
Update algo
Mitch-At-Work Aug 24, 2024
5efd619
Seperate logic to simplify
Mitch-At-Work Aug 24, 2024
1d9c783
Update after element detection
Mitch-At-Work Aug 26, 2024
7a4e49a
Algo works, now polish
Mitch-At-Work Aug 26, 2024
89a130b
Fix up IO to always detect actual distance if past window bounds
Mitch-At-Work Aug 26, 2024
6c71685
Reduce unneeded length
Mitch-At-Work Aug 26, 2024
0c98537
Fix up the window reference height
Mitch-At-Work Aug 26, 2024
7b8b0c1
Tidy up and ensure smoothness
Mitch-At-Work Aug 27, 2024
5d59358
Fix buffer sizes
Mitch-At-Work Aug 27, 2024
c5b853e
Update algo to account for dynamic size changes
Mitch-At-Work Aug 27, 2024
29f88de
Fix up reversed order lists
Mitch-At-Work Aug 27, 2024
c6a3cad
Update build and test
Mitch-At-Work Aug 27, 2024
4eb4177
Update
Mitch-At-Work Aug 27, 2024
f2a24d1
Type check and update average automeasure size
Mitch-At-Work Aug 27, 2024
b4a9a33
Type check stories fixup
Mitch-At-Work Aug 27, 2024
7c9d015
Update dynamic scrollview props
Mitch-At-Work Aug 27, 2024
dabb049
Fix up max index and remove scrollref from virtualizer hook in stories
Mitch-At-Work Aug 29, 2024
13bec55
Update virtualizer buffer removal, should be inverse
Mitch-At-Work Aug 29, 2024
518894b
Correctly handle partially visible elements
Mitch-At-Work Aug 29, 2024
a9f5994
Update
Mitch-At-Work Aug 29, 2024
43120ce
Fix up
Mitch-At-Work Aug 29, 2024
01139d9
Fix up flush sync
Mitch-At-Work Aug 29, 2024
3246d45
Remove force render and console log
Mitch-At-Work Aug 30, 2024
b7dd05f
Update
Mitch-At-Work Aug 30, 2024
4457e2d
Remove optionals
Mitch-At-Work Aug 30, 2024
c38f25b
Comment and remove unnessecary check
Mitch-At-Work Aug 30, 2024
21ae3fc
Cleanup
Mitch-At-Work Aug 30, 2024
3495ad4
Update virtualizer api
Mitch-At-Work Aug 30, 2024
6f743ae
Final build cleanup
Mitch-At-Work Aug 30, 2024
4aed451
Update changelog
Mitch-At-Work Aug 30, 2024
edd7073
Lint
Mitch-At-Work Aug 30, 2024
2f75783
Update virtualized combobox
Mitch-At-Work Aug 30, 2024
5682f9f
Fix up height calc on combobox
Mitch-At-Work Aug 31, 2024
795e81f
small comment updates
Mitch-At-Work Sep 4, 2024
e628416
Update comment
Mitch-At-Work Sep 6, 2024
9e8be32
Set ref to non-mutable
Mitch-At-Work Sep 23, 2024
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
@@ -0,0 +1,7 @@
{
Mitch-At-Work marked this conversation as resolved.
Show resolved Hide resolved
"type": "prerelease",
"comment": "BREAKING CHANGE (useVirtualizerDynamicMeasure): optimized with scrollPos state and children height reference, updated algorithm to be more accurate, and exported measurement hook",
"packageName": "@fluentui/react-virtualizer",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ const useStyles = makeStyles({
export const ComboboxVirtualizer = (props: Partial<ComboboxProps>) => {
const comboId = useId('combobox');

const itemHeight = 32; //This should match the height of each item in the listbox
//This should include the item height (32px) and account for rowGap (2px)
const itemHeight = 34;
const numberOfItems = 10000;

const { virtualizerLength, bufferItems, bufferSize, scrollRef } = useStaticVirtualizerMeasure({
const { virtualizerLength, bufferItems, bufferSize, scrollRef, containerSizeRef } = useStaticVirtualizerMeasure({
defaultItemSize: itemHeight,
direction: 'vertical',
});
Expand All @@ -43,6 +44,7 @@ export const ComboboxVirtualizer = (props: Partial<ComboboxProps>) => {
bufferItems={bufferItems}
bufferSize={bufferSize}
itemSize={itemHeight}
containerSizeRef={containerSizeRef}
>
{index => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ import type { SetStateAction } from 'react';
import type { Slot } from '@fluentui/react-utilities';
import type { SlotClassNames } from '@fluentui/react-utilities';

// @public
export type DynamicVirtualizerContextProps = Required<VirtualizerContextProps>;

// @public (undocumented)
export interface IndexedResizeCallbackElement {
// (undocumented)
handleResize: () => void;
}

// @public (undocumented)
export const renderVirtualizer_unstable: (state: VirtualizerState) => JSX.Element;

Expand Down Expand Up @@ -71,6 +80,7 @@ export const useDynamicVirtualizerMeasure: <TElement extends HTMLElement>(virtua
bufferItems: number;
bufferSize: number;
scrollRef: (instance: TElement | null) => void;
containerSizeRef: React_2.RefObject<number>;
};

// @public
Expand All @@ -80,6 +90,15 @@ export const useIntersectionObserver: (callback: IntersectionObserverCallback, o
observer: MutableRefObject<IntersectionObserver | undefined>;
};

// @public
export function useMeasureList<TElement extends HTMLElement & IndexedResizeCallbackElement = HTMLElement & IndexedResizeCallbackElement>(currentIndex: number, refLength: number, totalLength: number, defaultItemSize: number): {
widthArray: React_2.MutableRefObject<any[]>;
heightArray: React_2.MutableRefObject<any[]>;
createIndexedRef: (index: number) => (el: TElement) => void;
refArray: React_2.MutableRefObject<(TElement | null | undefined)[]>;
sizeUpdateCount: number;
};

// @public
export const useResizeObserverRef_unstable: (resizeCallback: ResizeCallbackWithRef) => (instance: HTMLElement | HTMLDivElement | null) => void;

Expand All @@ -89,6 +108,7 @@ export const useStaticVirtualizerMeasure: <TElement extends HTMLElement>(virtual
bufferItems: number;
bufferSize: number;
scrollRef: (instance: TElement | null) => void;
containerSizeRef: React_2.MutableRefObject<number>;
};

// @public (undocumented)
Expand All @@ -115,7 +135,7 @@ export const useVirtualizerStyles_unstable: (state: VirtualizerState) => Virtual
// @public
export const Virtualizer: FC<VirtualizerProps>;

// @public (undocumented)
// @public
export type VirtualizerChildRenderFunction = (index: number, isScrolling: boolean) => React_2.ReactNode;

// @public (undocumented)
Expand All @@ -125,6 +145,9 @@ export const virtualizerClassNames: SlotClassNames<VirtualizerSlots>;
export type VirtualizerContextProps = {
contextIndex: number;
setContextIndex: (index: number) => void;
contextPosition?: number;
setContextPosition?: (index: number) => void;
childProgressiveSizes?: React_2.MutableRefObject<number[]>;
};

// @public (undocumented)
Expand All @@ -141,16 +164,20 @@ export type VirtualizerDataRef = {
// @public (undocumented)
export type VirtualizerMeasureDynamicProps = {
defaultItemSize: number;
currentIndex: number;
virtualizerContext: DynamicVirtualizerContextProps;
numItems: number;
getItemSize: (index: number) => number;
direction?: 'vertical' | 'horizontal';
bufferItems?: number;
bufferSize?: number;
};

// @public (undocumented)
export type VirtualizerMeasureProps = {
defaultItemSize: number;
direction?: 'vertical' | 'horizontal';
bufferItems?: number;
bufferSize?: number;
};

// @public (undocumented)
Expand All @@ -169,13 +196,14 @@ export const VirtualizerScrollViewDynamic: React_2.FC<VirtualizerScrollViewDynam
export const virtualizerScrollViewDynamicClassNames: SlotClassNames<VirtualizerScrollViewDynamicSlots>;

// @public (undocumented)
export type VirtualizerScrollViewDynamicProps = ComponentProps<Partial<VirtualizerScrollViewDynamicSlots>> & Partial<Omit<VirtualizerConfigProps, 'itemSize' | 'numItems' | 'getItemSize' | 'children' | 'flagIndex'>> & {
export type VirtualizerScrollViewDynamicProps = ComponentProps<Partial<VirtualizerScrollViewDynamicSlots>> & Partial<Omit<VirtualizerConfigProps, 'itemSize' | 'numItems' | 'getItemSize' | 'children' | 'flagIndex' | 'virtualizerContext'>> & {
itemSize: number;
getItemSize?: (index: number) => number;
numItems: number;
children: VirtualizerChildRenderFunction;
imperativeRef?: RefObject<ScrollToInterface>;
enablePagination?: boolean;
virtualizerContext?: DynamicVirtualizerContextProps;
};

// @public (undocumented)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export type VirtualizerConfigState = {
* Tells the virtualizer to measure in the reverse direction (for column-reverse order etc.)
*/
reversed?: boolean;
/**
* Enables the isScrolling property in the child render function
* Default: false - to prevent nessecary render function calls
*/
enableScrollLoad?: boolean;
/**
* Pixel size of intersection observers and how much they 'cross over' into the bufferItems index.
* Minimum 1px.
Expand All @@ -69,8 +74,10 @@ export type VirtualizerConfigState = {

export type VirtualizerState = ComponentState<VirtualizerSlots> & VirtualizerConfigState;

// Virtualizer render function to procedurally generate children elements as rows or columns via index.
// Q: Use generic typing and passing through object data or a simple index system?
/**
* The main child render method of Virtualization
* isScrolling will only be enabled when enableScrollLoad is set to true.
*/
export type VirtualizerChildRenderFunction = (index: number, isScrolling: boolean) => React.ReactNode;

export type VirtualizerDataRef = {
Expand Down Expand Up @@ -109,16 +116,19 @@ export type VirtualizerConfigProps = {
virtualizerLength: number;

/**
* Defaults to 1/4th of virtualizerLength.
* Defaults to 1/4th (or 1/3rd for dynamic items) of virtualizerLength.
* RECOMMEND: Override this with a consistent value if using a dynamic virtualizer.
*
* Controls the number of elements rendered before the current index entering the virtualized viewport.
* Constraints:
* - Large enough to cover bufferSize (prevents buffers intersecting into the viewport during rest state).
* - Small enough that the end buffer and end index (start index + virtualizerLength) is not within viewport at rest.
* - Small enough that the virtualizer only renders a few items outside of view.
*/
bufferItems?: number;

/**
* Defaults to half of bufferItems size (in pixels).
* Defaults to half of bufferItems * itemSize size (in pixels).
* RECOMMEND: Override this with a consistent minimum item size value if using a dynamic virtualizer.
* The length (in pixels) before the end/start DOM index where the virtualizer recalculation will be triggered.
* Increasing this reduces whitespace on ultra-fast scroll, as additional elements
* are buffered to appear while virtualization recalculates.
Expand All @@ -130,6 +140,8 @@ export type VirtualizerConfigProps = {

/**
* Enables users to override the intersectionObserverRoot.
* RECOMMEND: DO NOT PASS THIS IN, as it can cause side effects
* when overlapping with other scroll views
*/
scrollViewRef?: React.MutableRefObject<HTMLElement | null>;

Expand All @@ -145,6 +157,12 @@ export type VirtualizerConfigProps = {
*/
reversed?: boolean;

/**
* Enables the isScrolling property in the child render function
* Default: false - to prevent nessecary render function calls
*/
enableScrollLoad?: boolean;

/**
* Callback for acquiring size of individual items
* @param index - the index of the requested size's child
Expand All @@ -171,6 +189,12 @@ export type VirtualizerConfigProps = {
* Imperative ref contains our scrollTo index functionality for user control.
*/
imperativeVirtualizerRef?: RefObject<VirtualizerDataRef>;

/**
* A ref that provides the size of container (vertical - height, horizontal - width), set by a resize observer.
Mitch-At-Work marked this conversation as resolved.
Show resolved Hide resolved
* Virtualizer Measure hooks provide a suitable reference.
*/
containerSizeRef: RefObject<number>;
};

export type VirtualizerProps = ComponentProps<Partial<VirtualizerSlots>> & VirtualizerConfigProps;
Loading
Loading