diff --git a/packages/rn-tester/js/examples/SectionList/SectionListExample.js b/packages/rn-tester/js/examples/SectionList/SectionListExample.js
index 622226b38f..8c10c79ac2 100644
--- a/packages/rn-tester/js/examples/SectionList/SectionListExample.js
+++ b/packages/rn-tester/js/examples/SectionList/SectionListExample.js
@@ -33,16 +33,50 @@ const {
StyleSheet,
Text,
View,
+ SectionList,
} = require('react-native');
-import type {Item} from '../../components/ListExampleShared';
-
const VIEWABILITY_CONFIG = {
minimumViewTime: 3000,
viewAreaCoveragePercentThreshold: 100,
waitForInteraction: true,
};
+const CONSTANT_SECTION_EXAMPLES = [
+ {
+ key: 'empty section',
+ data: [],
+ },
+ {
+ renderItem: renderStackedItem,
+ key: 's1',
+ data: [
+ {
+ title: 'Item In Header Section',
+ text: 'Section s1',
+ key: 'header item',
+ },
+ ],
+ },
+ {
+ key: 's2',
+ data: [
+ {
+ noImage: true,
+ title: '1st item',
+ text: 'Section s2',
+ key: 'noimage0',
+ },
+ {
+ noImage: true,
+ title: '2nd item',
+ text: 'Section s2',
+ key: 'noimage1',
+ },
+ ],
+ },
+];
+
const renderSectionHeader = ({section}) => (
SECTION HEADER: {section.key}
@@ -73,195 +107,92 @@ const EmptySectionList = () => (
);
-class SectionListExample extends React.PureComponent<{...}, $FlowFixMeState> {
- state:
- | any
- | {|
- data: Array- ,
- debug: boolean,
- filterText: string,
- inverted: boolean,
- logViewable: boolean,
- virtualized: boolean,
- |} = {
- data: genItemData(1000),
- debug: false,
- filterText: '',
- logViewable: false,
- virtualized: true,
- inverted: false,
+const renderItemComponent = setItemState => ({item, separators}) => {
+ if (isNaN(item.key)) {
+ return;
+ }
+ const onPress = () => {
+ const updatedItem = pressItem(item);
+ setItemState(updatedItem);
};
- _scrollPos = new Animated.Value(0);
- _scrollSinkY = Animated.event(
- [{nativeEvent: {contentOffset: {y: this._scrollPos}}}],
- {useNativeDriver: true},
- );
-
- _sectionListRef: ?React.ElementRef = null;
- _captureRef = ref => {
- this._sectionListRef = ref;
- };
-
- _scrollToLocation(sectionIndex: number, itemIndex: number) {
- this._sectionListRef &&
- this._sectionListRef.scrollToLocation({sectionIndex, itemIndex});
- }
-
- _setBooleanValue: string => boolean => void = key => value =>
- this.setState({[key]: value});
-
- render(): React.Node {
- const filterRegex = new RegExp(String(this.state.filterText), 'i');
- const filter = item =>
- filterRegex.test(item.text) || filterRegex.test(item.title);
- const filteredData = this.state.data.filter(filter);
- const filteredSectionData = [];
- let startIndex = 0;
- const endIndex = filteredData.length - 1;
- for (let ii = 10; ii <= endIndex + 10; ii += 10) {
- filteredSectionData.push({
- key: `${filteredData[startIndex].key} - ${
- filteredData[Math.min(ii - 1, endIndex)].key
- }`,
- data: filteredData.slice(startIndex, ii),
- });
- startIndex = ii;
- }
- return (
-
-
- {
- this.setState(() => ({filterText}));
- }}
- placeholder="Search..."
- value={this.state.filterText}
- />
-
- {renderSmallSwitchOption(
- 'virtualized',
- this.state.virtualized,
- this._setBooleanValue('virtualized'),
- )}
- {renderSmallSwitchOption(
- 'Log Viewable',
- this.state.logViewable,
- this._setBooleanValue('logViewable'),
- )}
- {renderSmallSwitchOption(
- 'Debug',
- this.state.debug,
- this._setBooleanValue('debug'),
- )}
- {renderSmallSwitchOption(
- 'Inverted',
- this.state.inverted,
- this._setBooleanValue('inverted'),
- )}
-
-
-
- scroll to:
-
-
-
- (
-
- )}
- ItemSeparatorComponent={info => (
-
- )}
- debug={this.state.debug}
- inverted={this.state.inverted}
- disableVirtualization={!this.state.virtualized}
- onRefresh={() => Alert.alert('onRefresh: nothing to refresh :P')}
- onScroll={this._scrollSinkY}
- onViewableItemsChanged={this._onViewableItemsChanged}
- refreshing={false}
- renderItem={this._renderItemComponent}
- renderSectionHeader={renderSectionHeader}
- renderSectionFooter={renderSectionFooter}
- stickySectionHeadersEnabled
- initialNumToRender={10}
- ListEmptyComponent={EmptySectionList}
- onEndReached={() =>
- Alert.alert(
- 'onEndReached called',
- 'You have reached the end of this list',
- )
- }
- onEndReachedThreshold={0}
- sections={[
- {
- key: 'empty section',
- data: [],
- },
- {
- renderItem: renderStackedItem,
- key: 's1',
- data: [
- {
- title: 'Item In Header Section',
- text: 'Section s1',
- key: 'header item',
- },
- ],
- },
- {
- key: 's2',
- data: [
- {
- noImage: true,
- title: '1st item',
- text: 'Section s2',
- key: 'noimage0',
- },
- {
- noImage: true,
- title: '2nd item',
- text: 'Section s2',
- key: 'noimage1',
- },
- ],
- },
- ...filteredSectionData,
- ]}
- style={styles.list}
- viewabilityConfig={VIEWABILITY_CONFIG}
- />
-
- );
- }
-
- _renderItemComponent = ({item, separators}) => (
+ return (
);
+};
- // This is called when items change viewability by scrolling into our out of
- // the viewable area.
- _onViewableItemsChanged = (info: {
+const onScrollToIndexFailed = (info: {
+ index: number,
+ c: number,
+ averageItemLength: number,
+}) => {
+ console.warn('onScrollToIndexFailed. See comment in callback', info);
+ /**
+ * scrollToLocation() can only scroll to viewable area.
+ * For any failure cases this callback will get triggered with `info` object
+ *
+ * The idea is to calculate a yPosition from `info` to call scrollResponder.scrollTo on.
+ *
+ * const scrollResponder = ref.current?.getScrollResponder();
+ * const positionY = some value we calculate from `info`;
+ * if (scrollResponder != null) {
+ * scrollResponder.scrollTo({x, y:positionY, animated: true});
+ * }
+ */
+};
+
+function SectionListExample(Props: {...}): React.Element {
+ const scrollPos = new Animated.Value(0);
+ const scrollSinkY = Animated.event(
+ [{nativeEvent: {contentOffset: {y: scrollPos}}}],
+ {useNativeDriver: true},
+ );
+ const [filterText, setFilterText] = React.useState('');
+ const [virtualized, setVirtualized] = React.useState(true);
+ 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 filterRegex = new RegExp(String(filterText), 'i');
+ const filter = item =>
+ filterRegex.test(item.text) || filterRegex.test(item.title);
+ const filteredData = data.filter(filter);
+ const filteredSectionData = [...CONSTANT_SECTION_EXAMPLES];
+
+ let startIndex = 0;
+ const endIndex = filteredData.length - 1;
+ for (let ii = 10; ii <= endIndex + 10; ii += 10) {
+ filteredSectionData.push({
+ key: `${filteredData[startIndex].key} - ${
+ filteredData[Math.min(ii - 1, endIndex)].key
+ }`,
+ data: filteredData.slice(startIndex, ii),
+ });
+ startIndex = ii;
+ }
+
+ const setItemPress = item => {
+ if (isNaN(item.key)) {
+ return;
+ }
+ const index = Number(item.key);
+ setData([...data.slice(0, index), item, ...data.slice(index + 1)]);
+ };
+
+ const ref = React.useRef>(null);
+ const scrollToLocation = (sectionIndex, itemIndex) => {
+ if (ref != null && ref.current?.scrollToLocation != null) {
+ ref.current.scrollToLocation({sectionIndex, itemIndex});
+ }
+ };
+
+ const onViewableItemsChanged = (info: {
changed: Array<{
key: string,
isViewable: boolean,
@@ -273,7 +204,7 @@ class SectionListExample extends React.PureComponent<{...}, $FlowFixMeState> {
...
}) => {
// Impressions can be logged here
- if (this.state.logViewable) {
+ if (logViewable) {
infoLog(
'onViewableItemsChanged: ',
info.changed.map((v: Object) => ({
@@ -285,24 +216,95 @@ class SectionListExample extends React.PureComponent<{...}, $FlowFixMeState> {
}
};
- _pressItem = (key: string) => {
- if (isNaN(key)) {
- return;
- }
- const index = Number(key);
- const itemState = pressItem(this.state.data[index]);
- this.setState(state => ({
- ...state,
- data: [
- ...state.data.slice(0, index),
- itemState,
- ...state.data.slice(index + 1),
- ],
- }));
- };
+ return (
+
+
+ setFilterText(text)}
+ placeholder="Search..."
+ value={filterText}
+ />
+
+ {renderSmallSwitchOption('Virtualized', virtualized, setVirtualized)}
+ {renderSmallSwitchOption('Log Viewable', logViewable, setLogViewable)}
+ {renderSmallSwitchOption('Debug', debug, setDebug)}
+ {renderSmallSwitchOption('Inverted', inverted, setInverted)}
+
+
+
+ scroll to:
+
+ scrollToLocation(Math.max(0, 2), 0)}
+ />
+
+
+ scrollToLocation(Math.max(0, 3), 0)}
+ />
+
+
+ scrollToLocation(Math.max(0, 6), 0)}
+ />
+
+
+
+ scrollToLocation(filteredSectionData.length - 1, 0)
+ }
+ />
+
+
+
+
+ (
+
+ )}
+ ItemSeparatorComponent={info => (
+
+ )}
+ debug={debug}
+ inverted={inverted}
+ disableVirtualization={!virtualized}
+ onRefresh={() => Alert.alert('onRefresh: nothing to refresh :P')}
+ onScroll={scrollSinkY}
+ onViewableItemsChanged={onViewableItemsChanged}
+ onScrollToIndexFailed={onScrollToIndexFailed}
+ refreshing={false}
+ renderItem={renderItemComponent(setItemPress)}
+ renderSectionHeader={renderSectionHeader}
+ renderSectionFooter={renderSectionFooter}
+ stickySectionHeadersEnabled
+ initialNumToRender={10}
+ ListEmptyComponent={EmptySectionList}
+ onEndReached={() =>
+ Alert.alert(
+ 'onEndReached called',
+ 'You have reached the end of this list',
+ )
+ }
+ onEndReachedThreshold={0}
+ sections={filteredSectionData}
+ style={styles.list}
+ viewabilityConfig={VIEWABILITY_CONFIG}
+ />
+
+ );
}
const styles = StyleSheet.create({
+ button: {
+ marginTop: 5,
+ },
customSeparator: {
backgroundColor: 'rgb(200, 199, 204)',
},
@@ -324,9 +326,8 @@ const styles = StyleSheet.create({
searchRow: {
paddingHorizontal: 10,
},
- scrollToRow: {
- flexDirection: 'row',
- alignItems: 'center',
+ scrollToColumn: {
+ flexDirection: 'column',
paddingHorizontal: 8,
},
separatorText: {