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

[pull] master from facebook:master #659

Merged
merged 10 commits into from
Mar 18, 2021
5 changes: 2 additions & 3 deletions Libraries/Components/ScrollView/ScrollViewStickyHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import type {LayoutEvent} from '../../Types/CoreEventTypes';

const AnimatedView = AnimatedImplementation.createAnimatedComponent(View);

export type Props = {
export type Props = $ReadOnly<{
children?: React.Element<any>,
nextHeaderLayoutY: ?number,
onLayout: (event: LayoutEvent) => void,
Expand All @@ -34,8 +34,7 @@ export type Props = {
scrollViewHeight: ?number,
nativeID?: ?string,
hiddenOnScroll?: ?boolean,
...
};
}>;

type State = {
measured: boolean,
Expand Down
37 changes: 16 additions & 21 deletions Libraries/Lists/FlatList.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import type {
ViewabilityConfigCallbackPair,
} from './ViewabilityHelper';
import type {RenderItemType, RenderItemProps} from './VirtualizedList';
import {keyExtractor as defaultKeyExtractor} from './VirtualizeUtils';

type RequiredProps<ItemT> = {|
/**
Expand Down Expand Up @@ -121,7 +120,7 @@ type OptionalProps<ItemT> = {|
* and as the react key to track item re-ordering. The default extractor checks `item.key`, then
* falls back to using the index, like React does.
*/
keyExtractor?: ?(item: ItemT, index: number) => string,
keyExtractor: (item: ItemT, index: number) => string,
/**
* Multiple columns can only be rendered with `horizontal={false}` and will zig-zag like a
* `flexWrap` layout. Items should all be the same height - masonry layouts are not supported.
Expand Down Expand Up @@ -157,6 +156,7 @@ export type Props<ItemT> = {
};

const defaultProps = {
...VirtualizedList.defaultProps,
numColumns: 1,
/**
* Enabling this prop on Android greatly improves scrolling performance with no known issues.
Expand Down Expand Up @@ -503,33 +503,28 @@ class FlatList<ItemT> extends React.PureComponent<Props<ItemT>, void> {
};

_keyExtractor = (items: ItemT | Array<ItemT>, index: number) => {
const {numColumns} = this.props;
const keyExtractor = this.props.keyExtractor ?? defaultKeyExtractor;

const {keyExtractor, numColumns} = this.props;
if (numColumns > 1) {
if (Array.isArray(items)) {
return items
.map((item, kk) =>
keyExtractor(((item: $FlowFixMe): ItemT), index * numColumns + kk),
)
.join(':');
} else {
invariant(
Array.isArray(items),
'FlatList: Encountered internal consistency error, expected each item to consist of an ' +
'array with 1-%s columns; instead, received a single item.',
numColumns,
);
}
invariant(
Array.isArray(items),
'FlatList: Encountered internal consistency error, expected each item to consist of an ' +
'array with 1-%s columns; instead, received a single item.',
numColumns,
);
return (
items
// $FlowFixMe[incompatible-call]
.map((it, kk) => keyExtractor(it, index * numColumns + kk))
.join(':')
);
} else {
// $FlowFixMe Can't call keyExtractor with an array
return keyExtractor(items, index);
}
};

_pushMultiColumnViewable(arr: Array<ViewToken>, v: ViewToken): void {
const {numColumns} = this.props;
const keyExtractor = this.props.keyExtractor ?? defaultKeyExtractor;
const {numColumns, keyExtractor} = this.props;
v.item.forEach((item, ii) => {
invariant(v.index != null, 'Missing index!');
const index = v.index * numColumns + ii;
Expand Down
7 changes: 2 additions & 5 deletions Libraries/Lists/SectionList.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ type OptionalProps<SectionT: SectionBase<any>> = {|
* falls back to using the index, like react does. Note that this sets keys for each item, but
* each overall section still needs its own key.
*/
keyExtractor?: ?(item: Item, index: number) => string,
keyExtractor: (item: Item, index: number) => string,
/**
* Called once when the scroll position gets within `onEndReachedThreshold` of the rendered
* content.
Expand All @@ -105,10 +105,6 @@ export type Props<SectionT> = {|
VirtualizedSectionListProps<SectionT>,
'renderItem',
>,
keyExtractor: $PropertyType<
VirtualizedSectionListProps<SectionT>,
'keyExtractor',
>,
...
},
>,
Expand All @@ -117,6 +113,7 @@ export type Props<SectionT> = {|
|};

const defaultProps = {
...VirtualizedSectionList.defaultProps,
stickySectionHeadersEnabled: Platform.OS === 'ios',
};

Expand Down
10 changes: 0 additions & 10 deletions Libraries/Lists/VirtualizeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,3 @@ export function computeWindowedRenderLimits(
}
return {first, last};
}

export function keyExtractor(item: any, index: number): string {
if (typeof item === 'object' && item?.key != null) {
return item.key;
}
if (typeof item === 'object' && item?.id != null) {
return item.id;
}
return String(index);
}
71 changes: 34 additions & 37 deletions Libraries/Lists/VirtualizedList.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ const infoLog = require('../Utilities/infoLog');
const invariant = require('invariant');
import VirtualizedListInjection from './VirtualizedListInjection';

import {
keyExtractor as defaultKeyExtractor,
computeWindowedRenderLimits,
} from './VirtualizeUtils';
import {computeWindowedRenderLimits} from './VirtualizeUtils';

import * as React from 'react';
import type {ScrollResponderType} from '../Components/ScrollView/ScrollView';
Expand Down Expand Up @@ -135,7 +132,7 @@ type OptionalProps = {|
* Reverses the direction of scroll. Uses scale transforms of -1.
*/
inverted?: ?boolean,
keyExtractor?: ?(item: Item, index: number) => string,
keyExtractor: (item: Item, index: number) => string,
/**
* Each cell is rendered using this element. Can be a React Component Class,
* or a render function. Defaults to using View.
Expand Down Expand Up @@ -306,6 +303,10 @@ type Props = {|
...OptionalProps,
|};

type DefaultProps = {|
keyExtractor: (item: Item, index: number) => string,
|};

let _usedIndexForKey = false;
let _keylessItemComponentName: string = '';

Expand All @@ -314,37 +315,26 @@ type State = {
last: number,
};

/**
* Default Props Helper Functions
* Use the following helper functions for default values
*/

// horizontalOrDefault(this.props.horizontal)
function horizontalOrDefault(horizontal: ?boolean) {
return horizontal ?? false;
}

// initialNumToRenderOrDefault(this.props.initialNumToRenderOrDefault)
function initialNumToRenderOrDefault(initialNumToRender: ?number) {
return initialNumToRender ?? 10;
}

// maxToRenderPerBatchOrDefault(this.props.maxToRenderPerBatch)
function maxToRenderPerBatchOrDefault(maxToRenderPerBatch: ?number) {
return maxToRenderPerBatch ?? 10;
}

// onEndReachedThresholdOrDefault(this.props.onEndReachedThreshold)
function onEndReachedThresholdOrDefault(onEndReachedThreshold: ?number) {
return onEndReachedThreshold ?? 2;
}

// scrollEventThrottleOrDefault(this.props.scrollEventThrottle)
function scrollEventThrottleOrDefault(scrollEventThrottle: ?number) {
return scrollEventThrottle ?? 50;
}

// windowSizeOrDefault(this.props.windowSize)
function windowSizeOrDefault(windowSize: ?number) {
return windowSize ?? 21;
}
Expand Down Expand Up @@ -375,7 +365,6 @@ function windowSizeOrDefault(windowSize: ?number) {
* 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
*
*/
class VirtualizedList extends React.PureComponent<Props, State> {
Expand Down Expand Up @@ -591,6 +580,22 @@ class VirtualizedList extends React.PureComponent<Props, State> {
}
}

static defaultProps: DefaultProps = {
keyExtractor: (item: Item, index: number) => {
if (item.key != null) {
return item.key;
}
if (item.id != null) {
return item.id;
}
_usedIndexForKey = true;
if (item.type && item.type.displayName) {
_keylessItemComponentName = item.type.displayName;
}
return String(index);
},
};

_getCellKey(): string {
return this.context?.cellKey || 'rootList';
}
Expand Down Expand Up @@ -799,14 +804,15 @@ class VirtualizedList extends React.PureComponent<Props, State> {
getItem,
getItemCount,
horizontal,
keyExtractor,
} = this.props;
const stickyOffset = this.props.ListHeaderComponent ? 1 : 0;
const end = getItemCount(data) - 1;
let prevCellKey;
last = Math.min(end, last);
for (let ii = first; ii <= last; ii++) {
const item = getItem(data, ii);
const key = this._keyExtractor(item, ii);
const key = keyExtractor(item, ii);
this._indicesToKeys.set(ii, key);
if (stickyIndicesFromProps.has(ii + stickyOffset)) {
stickyHeaderIndices.push(cells.length);
Expand Down Expand Up @@ -858,21 +864,6 @@ class VirtualizedList extends React.PureComponent<Props, State> {
_getSpacerKey = (isVertical: boolean): string =>
isVertical ? 'height' : 'width';

_keyExtractor(item: Item, index: number) {
if (this.props.keyExtractor != null) {
return this.props.keyExtractor(item, index);
}

const key = defaultKeyExtractor(item, index);
if (key === String(index)) {
_usedIndexForKey = true;
if (item.type && item.type.displayName) {
_keylessItemComponentName = item.type.displayName;
}
}
return key;
}

render(): React.Node {
if (__DEV__) {
const flatStyles = flattenStyle(this.props.contentContainerStyle);
Expand Down Expand Up @@ -1825,9 +1816,9 @@ class VirtualizedList extends React.PureComponent<Props, State> {
};

_createViewToken = (index: number, isViewable: boolean) => {
const {data, getItem} = this.props;
const {data, getItem, keyExtractor} = this.props;
const item = getItem(data, index);
return {index, item, key: this._keyExtractor(item, index), isViewable};
return {index, item, key: keyExtractor(item, index), isViewable};
};

_getFrameMetricsApprox = (
Expand Down Expand Up @@ -1863,13 +1854,19 @@ class VirtualizedList extends React.PureComponent<Props, State> {
inLayout?: boolean,
...
} => {
const {data, getItem, getItemCount, getItemLayout} = this.props;
const {
data,
getItem,
getItemCount,
getItemLayout,
keyExtractor,
} = this.props;
invariant(
getItemCount(data) > index,
'Tried to get frame for out of range index ' + index,
);
const item = getItem(data, index);
let frame = item && this._frames[this._keyExtractor(item, index)];
let frame = item && this._frames[keyExtractor(item, index)];
if (!frame || frame.index !== index) {
if (getItemLayout) {
frame = getItemLayout(data, index);
Expand Down
Loading