Skip to content

Commit

Permalink
Merge pull request #37258 from bang9/cherrypick-0.72-fix-virtualized-…
Browse files Browse the repository at this point in the history
…list-for-mvcp
  • Loading branch information
kelset authored May 22, 2023
2 parents 614d9f8 + 96d7c92 commit 42fc885
Show file tree
Hide file tree
Showing 10 changed files with 1,026 additions and 258 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ exports[`FlatList renders all the bells and whistles 1`] = `
<RCTRefreshControl />
<View>
<View
collapsable={false}
onLayout={[Function]}
>
<header />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ exports[`SectionList renders all the bells and whistles 1`] = `
<RCTRefreshControl />
<View>
<View
collapsable={false}
onLayout={[Function]}
>
<header
Expand Down
48 changes: 38 additions & 10 deletions packages/rn-tester/js/components/ListExampleShared.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
const React = require('react');

const {
ActivityIndicator,
Animated,
Image,
Platform,
Expand All @@ -33,16 +34,28 @@ export type Item = {
...
};

function genItemData(count: number, start: number = 0): Array<Item> {
function genItemData(i: number): Item {
const itemHash = Math.abs(hashCode('Item ' + i));
return {
title: 'Item ' + i,
text: LOREM_IPSUM.substr(0, (itemHash % 301) + 20),
key: String(i),
pressed: false,
};
}

function genNewerItems(count: number, start: number = 0): Array<Item> {
const dataBlob = [];
for (let i = start; i < count + start; i++) {
dataBlob.push(genItemData(i));
}
return dataBlob;
}

function genOlderItems(count: number, start: number = 0): Array<Item> {
const dataBlob = [];
for (let ii = start; ii < count + start; ii++) {
const itemHash = Math.abs(hashCode('Item ' + ii));
dataBlob.push({
title: 'Item ' + ii,
text: LOREM_IPSUM.substr(0, (itemHash % 301) + 20),
key: String(ii),
pressed: false,
});
for (let i = count; i > 0; i--) {
dataBlob.push(genItemData(start - i));
}
return dataBlob;
}
Expand Down Expand Up @@ -147,6 +160,12 @@ class SeparatorComponent extends React.PureComponent<{...}> {
}
}

const LoadingComponent: React.ComponentType<{}> = React.memo(() => (
<View style={styles.loadingContainer}>
<ActivityIndicator />
</View>
));

class ItemSeparatorComponent extends React.PureComponent<$FlowFixMeProps> {
render(): React.Node {
const style = this.props.highlighted
Expand Down Expand Up @@ -352,6 +371,13 @@ const styles = StyleSheet.create({
text: {
flex: 1,
},
loadingContainer: {
alignItems: 'center',
justifyContent: 'center',
height: 100,
borderTopWidth: 1,
borderTopColor: 'rgb(200, 199, 204)',
},
});

module.exports = {
Expand All @@ -362,8 +388,10 @@ module.exports = {
ItemSeparatorComponent,
PlainInput,
SeparatorComponent,
LoadingComponent,
Spindicator,
genItemData,
genNewerItems,
genOlderItems,
getItemLayout,
pressItem,
renderSmallSwitchOption,
Expand Down
71 changes: 62 additions & 9 deletions packages/rn-tester/js/examples/FlatList/FlatList-basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,22 @@ import {
ItemSeparatorComponent,
PlainInput,
SeparatorComponent,
LoadingComponent,
Spindicator,
genItemData,
genNewerItems,
genOlderItems,
getItemLayout,
pressItem,
renderSmallSwitchOption,
} from '../../components/ListExampleShared';

import type {Item} from '../../components/ListExampleShared';

const PAGE_SIZE = 100;
const NUM_PAGES = 10;
const INITIAL_PAGE_OFFSET = Math.floor(NUM_PAGES / 2);
const LOAD_TIME = 2000;

const VIEWABILITY_CONFIG = {
minimumViewTime: 3000,
viewAreaCoveragePercentThreshold: 100,
Expand All @@ -53,6 +60,8 @@ const VIEWABILITY_CONFIG = {
type Props = $ReadOnly<{||}>;
type State = {|
data: Array<Item>,
first: number,
last: number,
debug: boolean,
horizontal: boolean,
inverted: boolean,
Expand All @@ -66,13 +75,18 @@ type State = {|
onPressDisabled: boolean,
textSelectable: boolean,
isRTL: boolean,
maintainVisibleContentPosition: boolean,
previousLoading: boolean,
nextLoading: boolean,
|};

const IS_RTL = I18nManager.isRTL;

class FlatListExample extends React.PureComponent<Props, State> {
state: State = {
data: genItemData(100),
data: genNewerItems(PAGE_SIZE, PAGE_SIZE * INITIAL_PAGE_OFFSET),
first: PAGE_SIZE * INITIAL_PAGE_OFFSET,
last: PAGE_SIZE + PAGE_SIZE * INITIAL_PAGE_OFFSET,
debug: false,
horizontal: false,
inverted: false,
Expand All @@ -86,6 +100,9 @@ class FlatListExample extends React.PureComponent<Props, State> {
onPressDisabled: false,
textSelectable: true,
isRTL: IS_RTL,
maintainVisibleContentPosition: true,
previousLoading: false,
nextLoading: false,
};

/* $FlowFixMe[missing-local-annot] The type annotation(s) required by Flow's
Expand Down Expand Up @@ -209,6 +226,11 @@ class FlatListExample extends React.PureComponent<Props, State> {
this.state.isRTL,
this._setIsRTL,
)}
{renderSmallSwitchOption(
'Maintain content position',
this.state.maintainVisibleContentPosition,
this._setBooleanValue('maintainVisibleContentPosition'),
)}
{Platform.OS === 'android' && (
<View>
<TextInput
Expand All @@ -230,8 +252,12 @@ class FlatListExample extends React.PureComponent<Props, State> {
<Animated.FlatList
fadingEdgeLength={this.state.fadingEdgeLength}
ItemSeparatorComponent={ItemSeparatorComponent}
ListHeaderComponent={<HeaderComponent />}
ListFooterComponent={FooterComponent}
ListHeaderComponent={
this.state.previousLoading ? LoadingComponent : HeaderComponent
}
ListFooterComponent={
this.state.nextLoading ? LoadingComponent : FooterComponent
}
ListEmptyComponent={ListEmptyComponent}
// $FlowFixMe[missing-empty-array-annot]
data={this.state.empty ? [] : filteredData}
Expand All @@ -250,6 +276,8 @@ class FlatListExample extends React.PureComponent<Props, State> {
keyboardShouldPersistTaps="always"
keyboardDismissMode="on-drag"
numColumns={1}
onStartReached={this._onStartReached}
initialScrollIndex={Math.floor(PAGE_SIZE / 2)}
onEndReached={this._onEndReached}
onRefresh={this._onRefresh}
onScroll={
Expand All @@ -260,6 +288,11 @@ class FlatListExample extends React.PureComponent<Props, State> {
refreshing={false}
contentContainerStyle={styles.list}
viewabilityConfig={VIEWABILITY_CONFIG}
maintainVisibleContentPosition={
this.state.maintainVisibleContentPosition
? {minIndexForVisible: 0}
: undefined
}
{...flatListItemRendererProps}
/>
</View>
Expand All @@ -280,13 +313,33 @@ class FlatListExample extends React.PureComponent<Props, State> {
_getItemLayout = (data: any, index: number) => {
return getItemLayout(data, index, this.state.horizontal);
};
_onStartReached = () => {
if (this.state.first <= 0 || this.state.previousLoading) {
return;
}

this.setState({previousLoading: true});
setTimeout(() => {
this.setState(state => ({
previousLoading: false,
data: genOlderItems(PAGE_SIZE, state.first).concat(state.data),
first: state.first - PAGE_SIZE,
}));
}, LOAD_TIME);
};
_onEndReached = () => {
if (this.state.data.length >= 1000) {
if (this.state.last >= PAGE_SIZE * NUM_PAGES || this.state.nextLoading) {
return;
}
this.setState(state => ({
data: state.data.concat(genItemData(100, state.data.length)),
}));

this.setState({nextLoading: true});
setTimeout(() => {
this.setState(state => ({
nextLoading: false,
data: state.data.concat(genNewerItems(PAGE_SIZE, state.last)),
last: state.last + PAGE_SIZE,
}));
}, LOAD_TIME);
};
// $FlowFixMe[missing-local-annot]
_onPressCallback = () => {
Expand Down Expand Up @@ -343,7 +396,7 @@ class FlatListExample extends React.PureComponent<Props, State> {

_pressItem = (key: string) => {
this._listRef?.recordInteraction();
const index = Number(key);
const index = this.state.data.findIndex(item => item.key === key);
const itemState = pressItem(this.state.data[index]);
this.setState(state => ({
...state,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const {
ItemComponent,
PlainInput,
SeparatorComponent,
genItemData,
genNewerItems,
getItemLayout,
pressItem,
renderSmallSwitchOption,
Expand All @@ -46,7 +46,7 @@ class MultiColumnExample extends React.PureComponent<
numColumns: number,
virtualized: boolean,
|} = {
data: genItemData(1000),
data: genNewerItems(1000),
filterText: '',
fixedHeight: true,
logViewable: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const {
PlainInput,
SeparatorComponent,
Spindicator,
genItemData,
genNewerItems,
pressItem,
renderSmallSwitchOption,
renderStackedItem,
Expand Down Expand Up @@ -170,7 +170,7 @@ export function SectionList_scrollable(Props: {
const [logViewable, setLogViewable] = React.useState(false);
const [debug, setDebug] = React.useState(false);
const [inverted, setInverted] = React.useState(false);
const [data, setData] = React.useState(genItemData(1000));
const [data, setData] = React.useState(genNewerItems(1000));

const filterRegex = new RegExp(String(filterText), 'i');
const filter = (item: Item) =>
Expand Down
Loading

0 comments on commit 42fc885

Please sign in to comment.