/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow * @format */ import type { LayoutEvent } from '../../../types'; import type { ScrollEvent } from '../Types/CoreEventTypes'; import type { ViewToken } from '../ViewabilityHelper'; import type { FrameMetricProps, Item, Props, RenderItemProps, RenderItemType, Separators } from './VirtualizedListProps'; import RefreshControl from '../../../exports/RefreshControl'; import ScrollView from '../../../exports/ScrollView'; import View, { type ViewProps } from '../../../exports/View'; import StyleSheet from '../../../exports/StyleSheet'; import Batchinator from '../Batchinator'; import clamp from '../Utilities/clamp'; import infoLog from '../infoLog'; import { CellRenderMask } from './CellRenderMask'; import ChildListCollection from './ChildListCollection'; import FillRateHelper from '../FillRateHelper'; import StateSafePureComponent from './StateSafePureComponent'; import ViewabilityHelper from '../ViewabilityHelper'; import CellRenderer from './VirtualizedListCellRenderer'; import { VirtualizedListCellContextProvider, VirtualizedListContext, VirtualizedListContextProvider } from './VirtualizedListContext.js'; import { computeWindowedRenderLimits, keyExtractor as defaultKeyExtractor } from '../VirtualizeUtils'; import invariant from 'fbjs/lib/invariant'; import nullthrows from 'nullthrows'; import * as React from 'react'; export type { RenderItemProps, RenderItemType, Separators }; const __DEV__ = process.env.NODE_ENV !== 'production'; const ON_EDGE_REACHED_EPSILON = 0.001; let _usedIndexForKey = false; let _keylessItemComponentName: string = ''; type ScrollResponderType = any; type ViewStyleProp = $PropertyType; type ViewabilityHelperCallbackTuple = { viewabilityHelper: ViewabilityHelper, onViewableItemsChanged: (info: { viewableItems: Array, changed: Array, ... }) => void, ... }; type State = { renderMask: CellRenderMask, cellsAroundViewport: { first: number, last: number, }, }; /** * Default Props Helper Functions * Use the following helper functions for default values */ // horizontalOrDefault(this.props.horizontal) declare function horizontalOrDefault(horizontal: ?boolean): any; // initialNumToRenderOrDefault(this.props.initialNumToRender) declare function initialNumToRenderOrDefault(initialNumToRender: ?number): any; // maxToRenderPerBatchOrDefault(this.props.maxToRenderPerBatch) declare function maxToRenderPerBatchOrDefault(maxToRenderPerBatch: ?number): any; // onStartReachedThresholdOrDefault(this.props.onStartReachedThreshold) declare function onStartReachedThresholdOrDefault(onStartReachedThreshold: ?number): any; // onEndReachedThresholdOrDefault(this.props.onEndReachedThreshold) declare function onEndReachedThresholdOrDefault(onEndReachedThreshold: ?number): any; // getScrollingThreshold(visibleLength, onEndReachedThreshold) declare function getScrollingThreshold(threshold: number, visibleLength: number): any; // scrollEventThrottleOrDefault(this.props.scrollEventThrottle) declare function scrollEventThrottleOrDefault(scrollEventThrottle: ?number): any; // windowSizeOrDefault(this.props.windowSize) declare function windowSizeOrDefault(windowSize: ?number): any; declare function findLastWhere(arr: $ReadOnlyArray, predicate: (element: T) => boolean): T | null; /** * Base implementation for the more convenient [``](https://reactnative.dev/docs/flatlist) * and [``](https://reactnative.dev/docs/sectionlist) components, which are also better * documented. In general, this should only really be used if you need more flexibility than * `FlatList` provides, e.g. for use with immutable data instead of plain arrays. * * Virtualization massively improves memory consumption and performance of large lists by * maintaining a finite render window of active items and replacing all items outside of the render * window with appropriately sized blank space. The window adapts to scrolling behavior, and items * are rendered incrementally with low-pri (after any running interactions) if they are far from the * visible area, or with hi-pri otherwise to minimize the potential of seeing blank space. * * Some caveats: * * - Internal state is not preserved when content scrolls out of the render window. Make sure all * your data is captured in the item data or external stores like Flux, Redux, or Relay. * - This is a `PureComponent` which means that it will not re-render if `props` remain shallow- * equal. Make sure that everything your `renderItem` function depends on is passed as a prop * (e.g. `extraData`) that is not `===` after updates, otherwise your UI may not update on * changes. This includes the `data` prop and parent component state. * - In order to constrain memory and enable smooth scrolling, content is rendered asynchronously * offscreen. This means it's possible to scroll faster than the fill rate ands momentarily see * blank content. This is a tradeoff that can be adjusted to suit the needs of each application, * and we are working on improving it behind the scenes. * - By default, the list looks for a `key` or `id` prop on each item and uses that for the React key. * Alternatively, you can provide a custom `keyExtractor` prop. * - As an effort to remove defaultProps, use helper functions when referencing certain props * */ declare class VirtualizedList extends StateSafePureComponent { static contextType: typeof VirtualizedListContext, scrollToEnd(params?: ?{ animated?: ?boolean, ... }): any, scrollToIndex(params: { animated?: ?boolean, index: number, viewOffset?: number, viewPosition?: number, ... }): $FlowFixMe, scrollToItem(params: { animated?: ?boolean, item: Item, viewOffset?: number, viewPosition?: number, ... }): any, scrollToOffset(params: { animated?: ?boolean, offset: number, ... }): any, recordInteraction(): any, flashScrollIndicators(): any, getScrollResponder(): ?ScrollResponderType, getScrollableNode(): ?number, getScrollRef(): ?React.ElementRef | ?React.ElementRef, _getCellKey(): string, _getScrollMetrics: any, hasMore(): boolean, _getOutermostParentListRef: any, _registerAsNestedChild: any, _unregisterAsNestedChild: any, state: State, invertedWheelEventHandler: ?(ev: any) => void, constructor(props: Props): any, _checkProps(props: Props): any, static _createRenderMask(props: Props, cellsAroundViewport: { first: number, last: number, }, additionalRegions?: ?$ReadOnlyArray<{ first: number, last: number, }>): CellRenderMask, static _initialRenderRegion(props: Props): { first: number, last: number, }, static _ensureClosestStickyHeader(props: Props, stickyIndicesSet: Set, renderMask: CellRenderMask, cellIdx: number): any, _adjustCellsAroundViewport(props: Props, cellsAroundViewport: { first: number, last: number, }): { first: number, last: number, }, _findFirstChildWithMore(first: number, last: number): number | null, componentDidMount(): any, componentWillUnmount(): any, setupWebWheelHandler(): any, teardownWebWheelHandler(): any, static getDerivedStateFromProps(newProps: Props, prevState: State): State, _pushCells(cells: Array, stickyHeaderIndices: Array, stickyIndicesFromProps: Set, first: number, last: number, inversionStyle: ViewStyleProp): any, static _constrainToItemCount(cells: { first: number, last: number, }, props: Props): { first: number, last: number, }, _onUpdateSeparators: any, _isNestedWithSameOrientation(): boolean, _getSpacerKey: any, _keyExtractor(item: Item, index: number, props: { keyExtractor?: ?(item: Item, index: number) => string, ... }): any, render(): React.Node, componentDidUpdate(prevProps: Props): any, _averageCellLength: any, _cellRefs: { [string]: null | CellRenderer }, _fillRateHelper: FillRateHelper, _frames: { [string]: { inLayout?: boolean, index: number, length: number, offset: number, } }, _footerLength: any, _hasTriggeredInitialScrollToIndex: any, _hasInteracted: any, _hasMore: any, _hasWarned: { [string]: boolean }, _headerLength: any, _hiPriInProgress: boolean, _highestMeasuredFrameIndex: any, _indicesToKeys: Map, _lastFocusedCellKey: ?string, _nestedChildLists: ChildListCollection, _offsetFromParentVirtualizedList: number, _prevParentOffset: number, _scrollMetrics: any, _scrollRef: ?React.ElementRef, _sentStartForContentLength: any, _sentEndForContentLength: any, _totalCellLength: any, _totalCellsMeasured: any, _updateCellsToRenderBatcher: Batchinator, _viewabilityTuples: Array, _captureScrollRef: any, _computeBlankness(): any, _defaultRenderScrollComponent: any, _onCellLayout: any, _onCellFocusCapture(cellKey: string): any, _onCellUnmount: any, _triggerRemeasureForChildListsInCell(cellKey: string): void, measureLayoutRelativeToContainingList(): void, _onLayout: any, _onLayoutEmpty: any, _getFooterCellKey(): string, _onLayoutFooter: any, _onLayoutHeader: any, _renderDebugOverlay(): any, _selectLength(metrics: $ReadOnly<{ height: number, width: number, ... }>): number, _selectOffset(metrics: $ReadOnly<{ x: number, y: number, ... }>): number, _maybeCallOnEdgeReached(): any, _onContentSizeChange: any, _convertParentScrollMetrics: any, _onScroll: any, _scheduleCellsToRenderUpdate(): any, _onScrollBeginDrag: any, _onScrollEndDrag: any, _onMomentumScrollBegin: any, _onMomentumScrollEnd: any, _updateCellsToRender: any, _createViewToken: any, _getOffsetApprox: any, __getFrameMetricsApprox: (index: number, props: FrameMetricProps) => { length: number, offset: number, ... }, _getFrameMetrics: any, _getNonViewportRenderRegions: any, _updateViewableItems(props: FrameMetricProps, cellsAroundViewport: { first: number, last: number, }): any, } const styles = StyleSheet.create({ verticallyInverted: { transform: 'scaleY(-1)' }, horizontallyInverted: { transform: 'scaleX(-1)' }, debug: { flex: 1 }, debugOverlayBase: { position: 'absolute', top: 0, right: 0 }, debugOverlay: { bottom: 0, width: 20, borderColor: 'blue', borderWidth: 1 }, debugOverlayFrame: { left: 0, backgroundColor: 'orange' }, debugOverlayFrameLast: { left: 0, borderColor: 'green', borderWidth: 2 }, debugOverlayFrameVis: { left: 0, borderColor: 'red', borderWidth: 2 } }); export default VirtualizedList;