Why does TouchableOpacity automatically trigger onPress in ReactNative Expo Snack? - react-native

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

Related

TouchableHighlight not working although using the source code from official react native documentation

I'm a new react native developer and I have an issue with TouchableHighlight where it always shows an error "Error: React.Children.only expected to receive a single React element child." in addition while I remove it is work as usual and I assume if this issue come from my device/vscode/browser. Because I already follow the source code from https://reactnative.dev/docs/touchablehighlight but still show that error.
Error image
Image without TouchableHighlight tag
Here my code
render() {
return (
<View style={styles.container}>
<TouchableHighlight onPress={this.onPress}>
<View style={styles.button}>
<Text>Touch Here</Text>
</View>
</TouchableHighlight>
<View style={[styles.countContainer]}>
<Text style={[styles.countText]}>
{this.state.count ? this.state.count : null}
</Text>
</View>
</View>
);}
From the error message, the issue might happen if you pass Mutlipe child components to TouchableHighlight
From the docs:
TouchableHighlight must have one child (not zero or more than one). If you wish to have several child components, wrap them in a View
<TouchableHighlight onPress={onPress}>
<View style={styles.button}> // Mutlipe child components are wrapped in a View
<Text>Touch</Text> // component 1
<Text>Here</Text> // component 2
</View>
</TouchableHighlight>

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 prevent touch bubbling to parent elements

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>
);
}

React Native: View onPress does not work

I'm facing a weird problem. In my react native app, if I set onPress event to View it is not triggered but if I set the same to Text inside View, it fires. What am I missing here?
<View style={{backgroundColor: "red", padding: 20}}>
<Text onPress={()=> {
console.log('works');
}
}>X</Text>
</View>
<View style={{backgroundColor: "red", padding: 20}} onPress={()=> {
console.log('does not work');
}
}>
<Text>X</Text>
</View>
Why is this so? Is this an issue with React Native? I'm using version 0.43
You can use TouchableOpacity for onPress event.
View doesn't provide onPress prop.
<TouchableOpacity style={{backgroundColor: "red", padding: 20}} onPress={()=> {
console.log('does not work');
}
}>
<Text>X</Text>
</TouchableOpacity>
You can wrap the view with a TouchableWithoutFeedback and then use onPress and friends like usual. Also you can still block pointerEvents by setting the attribute on on the child view, it even blocks pointer events on the parent TouchableWithoutFeedback, its interesting, this was my need on Android, I didn't test on iOS:
https://facebook.github.io/react-native/docs/touchablewithoutfeedback.html
<TouchableWithoutFeedback onPressIn={this.closeDrawer}>
<Animated.View style={[styles.drawerBackground, styleBackground]} pointerEvents={isOpen ? undefined : 'none'} />
</TouchableWithoutFeedback>
Alternatively you can also provide onStartShouldSetResponder to your view, like so:
<View onStartShouldSetResponder={() => console.log("View click")}>
// some code here
</View>
You can use TouchableOpacity, TouchableHighlight, TouchableNativeFeedback, to achieve this. View component doesn't provide onPress as props. So you use these instead of that.
<TouchableNativeFeedback
onPress={this._onPressButton}
</TouchableNativeFeedback>
OR
<TouchableHighlight onPress={this._onPressButton}>
</TouchableHighlight>
OR
<TouchableOpacity onPress={this._onPressButton}>
</TouchableOpacity>
onPress doesn't work on <View> tag use <TouchableOpacity> instead of View
<View>
<TouchableOpacity onPress={() => 'call your function here'}>
</TouchableOpacity>
</View>
For this issue you can make use either
touchable(opacity,withoutfeedback,....)
or Pressable component which is currently available in react native Package like,
<TouchableOpacity onPress={()=>console.log("Pressed")}>
....
</TouchableOpacity>
or
<Pressable onPress={()=>console.log("Pressed")}>
....
</Pressable>
2021
If you're looking for a more extensive and future-proof way to handle touch-based input, check out the Pressable API.
Source: https://reactnative.dev/docs/touchablewithoutfeedback
A new pressable component is provided in 0.67 of react native, which can solve your problem. It runs anywhere
enter image description here
well we can make the View have a onPress props onStartShouldSetResponder and onResponderGrant
<View
onStartShouldSetResponder={() => true}
onResponderGrant={() => console.log("view pressed")}
>
</View>
You can use TouchableOpacity for that purpose
<TouchableOpacity onPress={() => {your code here}}>
//Your inner views here
</TouchableOpacity>
In View onPress will not work because onPress event is not supported in view tag.That is why it is not working but you can go to this link https://reactnative.dev/docs/view
You can use Pressable components which is react native core component and wrap your View or any other component in Pressable which don't have onPress prop.
Like this:
<Pressable onPress={()=>console.log('pressed')}>
<View>
<Text>Some Text</Text>
</View>
</Pressable>
Pressable Documentation
For anybody who's lookig for a solution to this, as of RN 0.63, there is a new Pressabe api. It might have rolled out a couple versions earlier but it works great for such use cases.
<Pressable onPress={onPressFunction}>
<Text onPress={() => {
console.log('works');
}}>X</Text>
</Pressable>

React Native detect tap on View

I’m writing a React Native app and I want to detect tap/clicks anywhere on the screen so I put an onClick handler on my <View> element but it doesn’t seem to be working. Here is my render function:
<View style={styles.container} onClick={this.onClick}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
What do I need to do?
For making any element to handle touch/click events in a React-Native UI, you need to put the element inside a TouchableOpacity, TouchableWithoutFeedback, TouchableNativeFeedback or TouchableHighlight element:
<TouchableHighlight onPress = { this.onClick }>
<View style={styles.container}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
</TouchableHighlight>
Hope that helps.
In React Native version > 55.3 you make check onPress events into your View if use onStartShouldSetResponder props.
Like example:
<View
style={{ flex: 1 }}
onStartShouldSetResponder={() => console.log('You click by View')}
>
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh} />
}
>
<Text>Awesome</Text>
</ScrollView>
</View>
In example I showed how you can get onPress event on View and not blocking other event behind them. Refresh control still work correct.
In my case the following works fine. You can use onTouchStart and onTouchEnd handlers on any View via props, for example:
<View onTouchStart={() => this.doSomething()} />
More information
This worked for me...
onTouchEnd={() => alert('TAPPED')}
The easiest way to do that:
<TouchableOpacity style={styles.container} onPress={()=> whateverFunc(parameter)}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</TouchableOpacity>
So, you need to replace the 'View' component to a 'TouchableOpacity' or any other Touchable component and you also need to replace the 'onClick' prop to 'onPress'. That's all. The wrapping of a view with a TouchableWhatever component is not necessary at all.