Using TouchableOpacity to scroll a FlatList
See original GitHub issue- I have reviewed the documentation
- I have searched existing issues
- I am using the latest React Native version
I am trying to implement a horizontally scrolling FlatList that is essentially a step-by-step ‘wizard’ ui. The FlatList (paging enabled, horizontal) has 3 to 7 items in the data array and I have ‘prev’ and ‘next’ buttons implemented with TouchableOpacity components in a separate view at the bottom of the screen. I have a custom View component that will represent the contents of each step.
Tapping next or prev should scroll to the next index in the FlatList. Using something like:
this.flatListRef.scrollToIndex({index: this.state.currentStepIndex - 1, animated: true});
If I run with the Remote Debugger active, everything works fine. If I don’t use the debugger, tapping the ‘previous’ or ‘next’ TouchableOpacity buttons never returns (appears to be in an infinite loop). (I see the memory usage climb into the multiple GB territory.)
Is this a bug? Am I doing something wrong? Thank you in advance for your time!
Environment
Environment: OS: macOS High Sierra 10.13.4 Node: 9.7.1 Yarn: Not Found npm: 5.6.0 Watchman: 4.9.0 Xcode: Xcode 9.3 Build version 9E145 Android Studio: 3.1 AI-173.4720617
Packages: (wanted => installed) react: ^16.3.0-alpha.2 => 16.3.0-alpha.2 react-native: ^0.54.2 => 0.54.2
Steps to Reproduce
Here’s my render method of the FlatList and NavView:
render() { console.log(‘Render newrequestscreen’, this.state) return ( <SafeAreaView style={baseStyles.safeAreaDark}>
<FlatList
ref={(ref) => { this.flatListRef = ref; }}
scrollEnabled={false}
initialNumToRender={2}
initialScrollIndex={0}
refreshing={false}
pagingEnabled={true}
horizontal
getItemLayout={(data, index) => (
{length: Dimensions.get('window').width, offset: Dimensions.get('window').width * index, index}
)}
data={this.state.flexItems}
showsHorizontalScrollIndicator = { false }
decelerationRate={0}
snapToInterval={Dimensions.get('window').width}
snapToAlignment={'center'}
renderItem={({item, index}) => {
return (
<NewRequestInputView item={item} >
</NewRequestInputView>
)
}
}
keyExtractor={(item) => item.type}/>
{this.renderNewRequestInputView()}
</SafeAreaView>
);
}
// Here are my callback functions for onPress:
_nextStep() {
console.log('next tapped...', this.flatListRef)
if (this.state.currentStepIndex < this.state.flexItems.length - 1) {
this.flatListRef.scrollToIndex({index: this.state.currentStepIndex + 1, animated: true});
this.setState({
currentStepIndex: this.state.currentStepIndex + 1
})
}
}
_previousStep() {
console.log('prev tapped...', this.flatListRef)
if (this.state.currentStepIndex > 0) {
this.flatListRef.scrollToIndex({index: this.state.currentStepIndex - 1, animated: true});
this.setState({
currentStepIndex: this.state.currentStepIndex - 1
})
}
}
Expected Behavior
I would expect this to work without running in the debugger the same way it works when running in the debugger.
Initial view:

Tap Next:

Tap Next again:

Actual Behavior
Tapping on next (or previous) shows the press, but never comes back and the UI is no longer responsive:

Issue Analytics
- State:
- Created 5 years ago
- Comments:6
Top Related StackOverflow Question
Here’s the latest, I re-worked things slightly, re-started my machine, clean/build in Xcode & Android Studio. This code seems to be working:
Update: If I change things so that my FlatList’s data and currentList props are not part of this.state, I can advance the scroll index via the TouchableOpacity press. The problem is, I would like to update the state so that a progress view shows the current step information (e.g. ‘Step x of y’).
Updating the state in the _nextStep() or _previousStep() functions shouldn’t cause an infinite loop condition, right? I thought the FlatList would only re-render when the data or extraData props changed. Like I said earlier, if I run in the debugger, I don’t go into an infinite loop.