react-native: FlatList item onPress not work the first time after refreshed
- Review the documentation: https://facebook.github.io/react-native
- Search for existing issues: https://github.com/facebook/react-native/issues
- Use the latest React Native release: https://github.com/facebook/react-native/releases
Environment
React Native Environment Info:
System:
OS: macOS High Sierra 10.13.5
CPU: x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz
Memory: 25.63 MB / 8.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 8.11.2 - /usr/local/bin/node
Yarn: 1.7.0 - /usr/local/bin/yarn
npm: 5.6.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 11.4, macOS 10.13, tvOS 11.4, watchOS 4.3
IDEs:
Android Studio: 3.1 AI-173.4819257
Xcode: 9.4.1/9F2000 - /usr/bin/xcodebuild
npmPackages:
react: 16.3.1 => 16.3.1
react-native: 0.56.0 => 0.56.0
npmGlobalPackages:
create-react-native-app: 1.0.0
react-native-cli: 2.0.1
react-native-scripts: 1.14.0
Description
FlatList has item with TouchableHighlight, and a RefreshControl attached.
onPress method of TouchableHighlight is not working the first time after onRefresh called.

If I scroll FlatList a bit after refreshed, then item onPress works fine.
// UPDATE: Android does not have this bug.
Reproducible Demo
Fresh project created by react-native init
import React, { Component } from "react";
import { Text, View, FlatList, TouchableOpacity, RefreshControl } from "react-native";
type Props = {};
export default class App extends Component<Props> {
constructor() {
super();
this.state = { refreshing: true, items: [] };
}
componentDidMount() {
this.refresh();
}
genItems = () => [0, 1, 2, 3, 4, 5];
refresh = () => {
this.setState({ refreshing: true, items: [] });
setTimeout(() => this.setState({ refreshing: false, items: this.genItems() }), 1500);
};
renderItem = ({ item }) => {
const text = `${item}`;
return (
<TouchableOpacity onPress={() => alert("pressed!")}>
<Text style={{ width: "100%", height: 48, backgroundColor: "white" }}>
{text}
</Text>
<View style={{ width: "100%", height: 1, backgroundColor: "gray" }} />
</TouchableOpacity>
);
};
render() {
return (
<View style={{ flex: 1, padding: 48 }}>
<FlatList style={{ flex: 1, backgroundColor: "#aaa", borderColor: "gray", borderWidth: 1 }}
renderItem={this.renderItem}
data={this.state.items}
keyExtractor={item => `${item}`}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.refresh}
/>
}
/>
</View>
);
}
}
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 20
- Comments: 50 (6 by maintainers)
Links to this issue
Commits related to this issue
- 代码有执行,但是刷新效果出不来,https://github.com/facebook/react-native/issues/20011 — committed to Clearives/ccM by Clearives 6 years ago
- fix: First press not working after pull to refresh (#30291) Summary: According to https://github.com/facebook/react-native/issues/20011, the first onPress will not work after pull to refresh. Dive i... — committed to facebook/react-native by rnike 4 years ago
Same issue!
@ravirajn22 , thanks! Passing
disableScrollViewPanResponderprop to myFlatListfixed the bug.The following are the details I found by debugging, may be some one more familiar with reactnative event plugin could take it further.
The issue happens because
responderInstis still kept hold by the ScrollView after all the events are fired whereas in case whereitems: []is commented in the setState, theresponderInstis correctly set to null.responderInstis a react component which will get all the touch events, how it works and set can be found insetResponderAndExtractTransferin ReactNativeRenderer-dev.js.targetInstis the react component on which the original touch happened.Nesting of components is like this View -> ScrollView -> (View -> Text ) * multiplied by number of list items
There are lots of events fired in following order
The partial flow is when we pull to refresh,
topTouchStartevent is fired which calls ScrollView’sscrollResponderHandleTouchStartwhich setsisTouchingtotrue.isTouchingdetermines if the ScrollView wants to becomeresponderInstwhentopScrollevent is firedisTouchingis set tofalseinsidescrollResponderHandleTouchEndwhenonTouchEndevent is fired . In our case this function is never called. Because ReactNativeBridgeEventPlugin’s extractEvents which determines which listeners (on the component) to call depends ontargetInst. Since we set items=[] in setState thetargetInstbecomes null and none of our listeners in ScrollVIew (ScrollView is the parent of items, since items is null we cannot know its parents now) are called after the items are cleared. Hence whenonTouchEndis firedscrollResponderHandleTouchEndof ScrollView is not called.Hope someone familiar with ScrollView responder system and react event system can take it further.
EDIT 1: In ScrollView setting
disableScrollViewPanResponder=truewill prevent this bug from happening, since it will prevent the ScrollView to become responder. But don’t use this, since I don’t know what regression it creates. Only purpose I added is for documenting.EDIT 2: Tagging people who might know about this, @shergin
@Rahulnagarwal perfect!
import { TouchableOpacity } from 'react-native-gesture-handler';it worked here for meI’ve been stuck with a similar issue I don’t know if its related or not. I’m developing for android only using a ScrollView and on a real device I can click buttons, they respond to being touched with the downstate etc but onPress doesn’t trigger. disableScrollViewPanResponder = {true} did not help in this case
I recognized that not only
FlatListitem, but every singleTouchableon the screen won’t callonPressafterFlatListrefreshed.I used a setTimeout to solve the issue
<RefreshControl refreshing={this.state.refresh} onRefresh={() => setTimeout(() => { this.refeshAction() }, 200) } title="Test />Same issue. Also setTimeout doesn’t work for me because of the breaking animation. Somebody has a better solution?
Same issue just push this inside the flatList
onRefresh={() => setTimeout(() => { this.refeshAction() }, 200) }is working for me !!try import { TouchableOpacity } from ‘react-native-gesture-handler’; It’s working properly
Same issue. Every touchable item on screen is not clickable after refresh
I 'm having this issue without the refresh on version 0.59.6
Any workarounds or news on a fix?
This reproes with ScrollView, not just FlatList.
setIntervalin the componentDidMount which calls refresh(), that doesn’t repro.Someone will need to dig into the ScrollView implementation and see if something funky is happening with the refresh control. It could also be somewhere in the ScrollableMixin or something like that.
This is the example I used:
It wasn’t me at all, it was all @yum650350. This was their first contribution to React Native!
same bug here with the simple FlatList “react-native”: “0.62.2”
<ScrollView disableScrollViewPanResponder={true} refreshControl={ <RefreshControl refreshing={this.state.refreshing} onRefresh={this.onRefresh.bind(this)} /> } >This worked for me
Thanks
This worked for me properly on a SectionList
Thanks a lot!
me too ,0.61.4
I don’t understand why this hasn’t been fixed yet. It only happens on Android
I’m really struggling with that. I don’t use
Refreshcontrolbut rather remove an item from the array.Here my setup
Here the process
FlatList(data={data})renderItemis wrapped in aTouchableOpacityrenderIteman ID gets stored in the hookFlatListre-renders and removes the itemI tried
import { TouchableOpacity } from 'react-native-gesture-handler'as @souzaluiz suggested but it has no effect.Please help !!!
disableScrollViewPanResponder = {true} fix the bug
The workaround
setTimeout with 200ms delayworks for me, but the refresh indicator has some animation problem.