React Native prevent touch bubbling to parent elements - react-native

If I want to prevent the onPress event on the View component propagating to the parent Touchable for the following Sample component, what's the best option other than wrapping the child view in a Touchable please?
export default function Sample (): Element<*> {
return(
<TouchableOpacity>
<View>
<Text>Sample</Text>
</View>
</TouchableOpacity>
);
}

In my case I simply put the View inside another TouchableOpacity (with activeOpacity to 1 to block any graphic effect):
export default function Sample (): Element<*> {
return(
<TouchableOpacity>
<TouchableOpacity activeOpacity={1}>
<View>
<Text>Sample</Text>
</View>
</TouchableOpacity>
</TouchableOpacity>
);
}

Related

Why does TouchableOpacity automatically trigger onPress in ReactNative Expo Snack?

I have a small ReactNative app in Expo Snack that includes a single components with a TouchableOpacity.
export default function AssetExample() {
function clicked() {
alert('clicked')
}
return (
<View style={styles.container}>
<TouchableOpacity onPress={clicked()}>
<Text style={styles.paragraph}>
Click the icon
</Text>
<Image style={styles.logo} source={require('../assets/snack-icon.png')} />
</TouchableOpacity>
</View>
);
}
Every time the app is started the alert is shown, meaning TouchableOpacity triggers onPress. Why? And how can I circumvent this?
You should pass the reference of your function to TouchableOpacity like this
<TouchableOpacity onPress={clicked}>
</TouchableOpacity>
or pass it with arrow function
<TouchableOpacity onPress={()=> clicked()}>
</TouchableOpacity>
so it will be called inside TouchableOpacity component whenever required (button click), otherwise it will be called only one time during render phase.
See these docs for handling events in React https://reactjs.org/docs/handling-events.html

How to cancel onPress in React Native

I have a TouchableHighlight zone in my component.
I would like to trigger _onPress method for a quick tap, and _onLongPress for a longer tap.
This works, but _onPress method is always triggered when I release the tap.
How can I do to trigger only one of these methods depending on short tap or long tap ?
class MyClass extends React.Component {
_onPress = () => {
console.log("Press")
}
_onLongPress = () => {
console.log("LongPress")
}
render() {
return (
<TouchableHighlight
style={styles.touchable}
underlayColor="white"
delayPressIn={2000}
onPress={this._onPress}
onPressIn={this._onLongPress}
>
<View style={styles.box}>
<Image style={styles.logo} source={this.state.logo.id} />
</View>
</TouchableHighlight>
)
}
}
Many thanks :)
According to the doc, you can pass both onPress and onLongPress props directly to the TouchableHighlight component, since it inherits all the props available from TouchableWithoutFeedback.
<TouchableHighlight
onPress={this._onPress}
onLongPress={this._onLongPress}
delayLongPress={2000}
...
>
...
</TouchableHighlight >
Just one of the two events will be triggered.
Here you can try an example of what I'm talking about.
TouchableHighlight inherits all props from TouchableWithoutFeedback ,rather than using onPressIn which you are trying to use in your code, you can use long and short press. So whatever you are trying will not work in this case.
You can use both TouchableHighlight TouchableWithoutFeedBack, aa both have the same props. It
have both onLongPress for long press and onPress for short press funtionality which you can fulfill your requirement.
<TouchableHighlight
style={styles.button}
onPress={this.onPress}
onLongPress={this.onPress2}
>
<Text> Touch Here </Text>
</TouchableHighlight>
and,
<TouchableWithoutFeedBack
style={styles.button}
onPress={this.onPress}
onLongPress={this.onPress2}
>
<Text> Touch Here </Text>
</TouchableWithoutFeedBack>
Hope this helps.....Thanks :)

React native onPress with TouchableWithoutFeedback is not working

I am developing a simple React Native application for learning purpose. I am just taking my initial step to get into the React Native world. But in this very early stage, I am having problems. I cannot get a simple touch event working. I am implementing touch event using TouchableWithoutFeedback. This is my code.
class AlbumList extends React.Component {
constructor(props)
{
super(props)
this.state = {
displayList : true
}
}
componentWillMount() {
this.props.fetchAlbums();
}
albumPressed(album)
{
console.log("Touch event triggered")
}
renderAlbumItem = ({item: album}) => {
return (
<TouchableWithoutFeedback onPress={this.albumPressed.bind(this)}>
<Card>
<CardSection>
<Text>{album.artist}</Text>
</CardSection>
<CardSection>
<Text>{album.title}</Text>
</CardSection>
</Card>
</TouchableWithoutFeedback>
)
}
render() {
let list;
if (this.state.displayList) {
list = <FlatList
data={this.props.albums}
renderItem={this.renderAlbumItem}
keyExtractor={(album) => album.title}
/>
}
return (
list
)
}
}
const mapStateToProps = state => {
return state.albumList;
}
const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({
fetchAlbums : AlbumListActions.fetchAlbums
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(AlbumList);
As you can see, I am implementing touch event on the list item. But it is not triggering at all when I click on the card on Simulator. Why? How can I fix it?
You should wrap your content in component like this:
<TouchableWithoutFeedback>
<View>
<Your components...>
</View>
</TouchableWithoutFeedback>
TouchableWithoutFeedback always needs to have child View component. So a component that composes a View isn't enough.
So instead of
<TouchableWithoutFeedback onPressIn={...} onPressOut={...} onPress={...}>
<MyCustomComponent />
</TouchableWithoutFeedback>
use:
<TouchableWithoutFeedback onPressIn={...} onPressOut={...} onPress={...}>
<View>
<MyCustomComponent />
</View>
</TouchableWithoutFeedback>
See the github issue for more info
Can be used with <TouchableOpacity activeOpacity={1.0}> </TouchableOpacity>
For those who struggle with this issue in react-native 0.64, and wrapping it in just a View doesn't work, try this:
<TouchableWithoutFeedback onPress={onPress}>
<View pointerEvents="none">
<Text>Text</Text>
</View>
</TouchableWithoutFeedback>
In my case i accidentally imported TouchableWithoutFeedback from react-native-web instead of react-native. After importing from react-native everything worked as expected.
In more recent React Native versions, just use Pressable instead:
https://reactnative.dev/docs/pressable
In my case, there was a shadow underneath, which caused instability. What I did to solve it was quite simple: zIndex: 65000
<View style={{ zIndex: 65000 }}>
<TouchableWithoutFeedback onPressIn={() => {}>
<View>
</View>
</TouchableWithoutFeedback>
</View>

React Native: can't call a parent method from child

I have this function in parent component, and I am trying to call this method/function in child , like so:
buttonPressed = () => {
console.log('button pressed')
}
<childComp ref={ref => this.feedback = ref}
onPress={this.buttonPressed}
/>
in child:
<Animated.View>
... // other views
<View>
<TouchableOpacity onPress={this.props.buttonPressed}> // calling here
...
</TouchableOpacity>
</View>
</Animated.View>
No matter what I tried , it didn't work.
you are passing onPress prop to child and calling buttonPressed in child. it should be like this :
<Animated.View>
... // other views
<View>
<TouchableOpacity onPress={this.props.onPress}> // calling here
...
</TouchableOpacity>
</View>
</Animated.View>
I think that in child component you should call to this.props.onPress(), because the name of the property thar you are passing is onPress. Also, don't forget to put () when you want to call the function. So it should be:
<Animated.View>
... // other views
<View>
<TouchableOpacity onPress={this.props.onPress()}> // calling here
...
</TouchableOpacity>
</View>
</Animated.View>

Click listener in flatlist

How can I add click listener in Flatlist?
My code:
renderItem({item, index}){
return <View style = {{
flex:1,
margin: 5,
minWidth: 170,
maxWidth: 223,
height: 304,
maxHeight: 304,
backgroundColor: '#ccc',
}}/>
}
render(){
return(<FlatList
contentContainerStyle={styles.list}
data={[{key: 'a'}, {key: 'b'},{key:'c'}]}
renderItem={this.renderItem}
/>);
}
}
Update 1: I used button but it is not working in Flatlist. However using only button instead of Flatlist, it works. Why is it not working in Flatlist renderItem?
_listener = () => {
alert("clicked");
}
renderItem({item, index}){
return<View>
<Button
title = "Button"
color = "#ccc"
onPress={this._listener}
/>
</View>
}
I used TouchableWithoutFeedback. For that, you need to add all the renderItem elements (i.e your row) into the TouchableWithoutFeedback. Then add the onPress event and pass the FaltList item to the onPress event.
import {View, FlatList, Text, TouchableWithoutFeedback} from 'react-native';
render() {
return (
<FlatList style={styles.list}
data={this.state.data}
renderItem={({item}) => (
<TouchableWithoutFeedback onPress={ () => this.actionOnRow(item)}>
<View>
<Text>ID: {item.id}</Text>
<Text>Title: {item.title}</Text>
</View>
</TouchableWithoutFeedback>
)}
/>
);
}
actionOnRow(item) {
console.log('Selected Item :',item);
}
You need to wrap your row element (inside your renderItem method) inside <TouchableWithoutFeedback> tag. TouchableWithoutFeedback takes onPress as it's prop where you can provide onPress event.
For TouchableWithoutFeedback refer this link
I used TouchableOpacity. and it's working great.This will give you click feedback. which will not be provided by TouchableWithoutFeedback. I did the following:
import { View, Text, TouchableOpacity } from "react-native";
.
.
.
_onPress = () => {
// your code on item press
};
render() {
<TouchableOpacity onPress={this._onPress}>
<View>
<Text>List item text</Text>
</View>
</TouchableOpacity>
}
If you are facing flatlist row first click issue
please add below property to flatlist.
disableScrollViewPanResponder = {true}
The Pressable component is now preferred over TouchableWithoutFeedback (and TouchableOpacity). According to the React Native docs for TouchableWithoutFeedback:
If you're looking for a more extensive and future-proof way to handle touch-based input, check out the Pressable API.
Example implementation:
import { Pressable } from "react-native";
render() {
return(
<FlatList
contentContainerStyle={styles.list}
data={[{key: 'a'}, {key: 'b'}, {key:'c'}]}
renderItem={({item}) => (
<Pressable onPress={this._listener}>
// BUILD VIEW HERE, e.g. this.renderItem(item)
</Pressable>
)}
/>
);
}
References
TouchableWithoutFeedback (React Native): https://reactnative.dev/docs/touchablewithoutfeedback
Pressable (React Native): https://reactnative.dev/docs/pressable
you dont need to add Touchable related component into your Flatlist renderItem. Just pass onTouchStart prop to your Flatlist.
in example:
<FlatList
style={themedStyles.flatListContainer}
data={translations}
renderItem={renderItem}
keyExtractor={(item, index) => `${item.originalText}____${index}`}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
ListEmptyComponent={renderEmptyListComponent}
onTouchStart={onBackgroundPressed}
/>