Touch handler not called with React Native - reactjs

I just started learning React Native and ran into this: I've created a component which has a TouchableHighlight within it, and I assigned a handler function to it, but it doesn't seem like it is getting called. Here is my component:
import React, {Component} from 'react';
import {
Text,
View,
TouchableHighlight
} from 'react-native';
export default class Component1 extends Component<{}> {
componentWillMount() {
console.log("hi there");
this.setState({age: 22});
}
handlePress() {
this.setState(prevState => ({ age: prevState.age + 1 }));
console.log("updated age");
}
render() {
return (
<View>
<View>
<Text>
{this.props.name}
{"\n"}
{this.state.age}
</Text>
</View>
<View>
<TouchableHighlight onPress={() => this.handlePress}>
<View>
<Text>Become older</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
}
}
When I tap the "become older" view nothing is logged to the terminal (I'm using react-native log-android.
Thank you for helping out :)

Inside the onPress, it should be a function. You are using arrow function so, you should call the function handlePress:
This part:
<TouchableHighlight onPress={() => this.handlePress}>
Should be:
<TouchableHighlight onPress={() => this.handlePress()}>
But if you are just calling the function, so you just need to pass it in like:
<TouchableHighlight onPress={this.handlePress}>

You have a syntax error.
<TouchableHighlight onPress={() => this.handlePress}>
should be
<TouchableHighlight onPress={() => this.handlePress()}>
or
<TouchableHighlight onPress={this.handlePress}>

Related

How to use navigation using functional component - react native

How can I use navigation using class component, the screens that I currently have on my app are functional components, and this is how I'm able to navigate from one page to another, but If try to implement this using functional comopenent it doesn't work.
export default function Activity({navigation}) {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
How Can I implemented in here :/
I tried
this.props.navigation.navigate('Home')
and I got the following error/warning
cannot update a component while rendering a different component
export default class App extends React.Component {
render() {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
For my navigation, I had to add at the beginning of the file this importation
import { useNavigation } from '#react-navigation/native'
And in my functional component
const navigation = useNavigation()
Like this :

Can't create function outside render in react native 0.61.1

I just created new react native app and trying to create a function and console.log onpress of TouchableOpacity but it is giving error that functionName is not defined.
Here is my code:
import React, { Component } from 'react';
import { Text, View, ScrollView, StyleSheet, TouchableOpacity } from 'react-native';
export default class Home extends Component {
functionName = () => {
console.log('function called');
}
render() {
return (
<ScrollView contentContainerStyle={styles.container}>
<TouchableOpacity onPress={functionName()}>
<Text> Home {sliderApi} </Text>
</TouchableOpacity>
</ScrollView>
)
}
}
But when I put functionName in render method it works fine.
Replace
<TouchableOpacity onPress={functionName()}>
with
<TouchableOpacity onPress={this.functionName}>
or with
<TouchableOpacity onPress={() => this.functionName()}>
Just for knowledge:
there is no difference between {this.functionName} and {() => this.functionName()}. The reason to use arrow function "() =>" is we are calling function with parentheses () like "this.functionName()". When we call function with parentheses () it will get called directly when the code will get executed. But when we want to call the function only when "onPress or Any event" fire of "TouchableOpacity or Any component" we have to use it with arrow function "() =>" or we just have to call it like "this.functionName".
you are calling the function in onPress event in wrong way. Try replacing the following line:
<TouchableOpacity onPress={functionName()}>
with
<TouchableOpacity onPress={() => this.functionName()}>

Proper use of onChangeText in React Native

I am fairly new to React Native and I have problem with using onChangeText.
I am trying to have a TextInput to type in a word and updating a state. When I use onChangeText I can only type 1 symbol at a time until it re-renders. I can keep the value by using
value = {this.state.text} but the input field still lose focus everytime I write a letter.
I have also tried using onBlur and onSubmitEditing with no success.
This is my current code. Which is inside render().
<View style={{padding: 10}}>
<TextInput
onChangeText={(text) => { this.setState({text: text})} }
/>
<TouchableHighlight style={styles.button} onPress={this.handlePress.bind(this)}>
<Text style={styles.buttonText}>Login</Text>
</TouchableHighlight>
<Text style={{padding: 10, fontSize: 42}}>
{this.state.text}
</Text>
</View>
So by using this method I can currently only write one letter at a time as this.state.text will only consist of one letter at a time.
Any help appreciated.
Example
SOLVED
I used react-native-tab-view which uses it's own router.
I wrote my code as this
And as you see the rendering part happens outside of return(). That's what caused my problem.
I've removed react-native-tab-view and rewritten it like this
<TextInput style={styles.input}
placeholder='username'
onChangeText={(text) => { this.setState({ username: text})}}>
</TextInput>
You need { } to open and close the function block, else it return the setState
() => callFn is equivalent with () => {return callFn} so you return your setState call.
You need here () => {callFn}
And remove the {this.state.text} from your <Text> tag, that will trigger rerender every time you change the state
Try with this full component hope so this helpfull for u.
'use strict';
import React, { Component } from "react";
import { Text, View, TextInput } from 'react-native';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
text:''
};
}
render() {
let {text}=this.state;
return (
<View style={{padding: 10}}>
<TextInput onChangeText={(text) => { this.setState({ text: text})}}/>
<Text style={{padding: 10, fontSize: 42}}>
{text}
</Text>
</View>
)
}
}
export default Home;
It is not best practice to create functions within component props. This will always force a re-render even if nothing was changed due to the fact that the prop value is a new function.
Try it like this.
I also gave you a way to have multiple text inputs without creating a single inline function by use of "currying", along with making them into controlled inputs whereby their value is "controlled" by the state. Socialism in React!
'use strict';
import React, { Component } from "react";
import { Text, View, TextInput, StyleSheet } from 'react-native';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
name:''
email:''
nameError:''
emailError:''
};
}
onChangeText = name => text => this.setState({ [name]: text });
render() {
let { name, email, nameError, emailError } = this.state;
return (
<View style={styles.container}>
<TextInput onChangeText={this._onChangeText("name")} value={name} />
<Text style={styles.text}>{nameError}</Text>
<TextInput onChangeText={this._onChangeText("email"} value={email} />
<Text style={styles.text}>{emailError}</Text>
</View>
)
}
}
const styles = StyleSheet.create({
text: {
padding: 10,
fontSize: 42
},
container: {
padding: 10
}
});
export default Home;

Reloading an animation React-native-animatable library

guy's I'm using the react-native-animatable library. Basically, when I load my app the animation runs, however, when I go to another tab and return to the initial page the animation doesn't run anymore. I think it's because it' doesn't get reloaded anymore and I was wondering how to reload a component. As you can see the View has an animation prop which is the animation which has to be loaded.
import React, { Component } from 'react';
import { Text, Button, StyleSheet, Image, ImageBackground, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import LinearGradient from 'react-native-linear-gradient';
import {Fonts} from '../components/Fonts';
import { createAnimatableComponent, View, } from 'react-native-animatable';
class Home extends React.Component {
render() {
return (
<View style={styles.container}>
<View animation='bounceInLeft'
style={styles.container1}>
<View style={styles.card1}>
<ImageBackground
source={require('../images/pictures/runop.jpg')}
style={{width:'100%', height:200, }}>
<Text
style={{fontSize:30, alignSelf:'center', color:'white',
fontFamily:Fonts.Nunito}}
> Sport Schema's</Text>
</ImageBackground>
</View>
</View>
<View animation='bounceInRight' style={styles.container2}>
<View style={styles.card2}>
<Image
source={require('../images/pictures/foodop.jpg')}
style={{width:'100%', height:200}}/>
</View>
</View>
<View animation='bounceInLeft' style={styles.container3}>
<View style={styles.card3}>
<Image
source={require('../images/pictures/blogop.jpg')}
style={{width:'100%', height:200}}/>
</View>
</View>
</View>
);
}
}
Thanks for your help. I eventually got it to work with a different method.
I used the withNavigationFocus from react-navigation to get the isFocused props of the current screen. Then i just used an if statement if screen is focused then run animation else dont.
import {withNavigationFocus} from 'react-navigation';
class Profile extends React.Component {
constructor(props) {
super(props);
}
render()
// This checks if current screen is focused then run the animation otherwise dont.
{
if (this.props.isFocused && this.animation) {
this.animation.bounce(800)
}
return (
<View ref={(ref) => {this.animation = ref;}}
style={styles.container3}>
<View style={styles.card3}>
<Text> hii</Text>
</View>
</View>
);
}
}
});
export default withNavigationFocus(Profile); // <- dont forget this!!
If you are using react-navigation, below solution might work for you.
Create a function which would start the animation after some milliseconds and pass it to the next screen as params. Example,
SCREEN A
animateFunction() {
setTimeout(() => {
// start your animation
}, 100);
}
navigation.navigate(SCREEN_NAME, { startPrevScreenAnimation: animateFunction });
And in the next screen call that function when the component unmounts (componentWillUnmount()). Example,
SCREEN B
componentWillUnmount() {
this.props.navigation.state.params.startPrevScreenAnimation();
}
I said some milliseconds because you would want the animation to start once the screen transition is complete.
OR
Add a listener to your screen which fires an event when the screen is in focus.
if (this.props.navigation) {
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
() => { // Run your animation },
);
}

Click Item in ListView React-Native not working

i am new in react-native and i want to press to to specific item in ListView, but when i click to item wich i want to select i didn't get console log message and i didn't get any errors so my code look like this
in renderRow my code look like this
renderRow(record) {
return (
<View style={styles.row}>
<TouchableHighlight onPress={() => this._pressRow()}>
<View style={styles.info}>
<Text style={styles.items}>{record.nom}</Text>
</View>
</TouchableHighlight>
</View>
);
}
and _pressRow function simple console log
_pressRow (rowID: number) {
console.log("clicked");
}
and render function
render() {
return (
<ScrollView scrollsToTop={false} style={styles.menu}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</ScrollView>
);
}
how can i resolve this issue and thanks.
Are you using the autobind-decorator? Using your code as is the _pressRow method won't be triggered. When I add the autobind decorator or change _pressRow into a fat-arrow function the console.log does work for me:
import React, { Component } from 'react'
import { View, TouchableHighlight, Text, ScrollView, ListView } from 'react-native'
_pressRow = (rowID: number) => {
console.log("clicked")
}
class App extends Component {
constructor(props) {
super(props)
this.dataSource = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
})
this.state = {
dataSource: this.dataSource.cloneWithRows([
{ nom: 'a' },
{ nom: 'b' },
]),
}
}
renderRow(record) {
return (
<View>
<TouchableHighlight onPress={() => this._pressRow()}>
<View>
<Text>{record.nom}</Text>
</View>
</TouchableHighlight>
</View>
)
}
render() {
return (
<ScrollView scrollsToTop={false}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</ScrollView>
)
}
}
export default App
change the this._pressRow() to this._pressRow.bind(this) if your function is in your Class
I used TouchableHighlight to wrap "un-pressable" component (accompany with changing this._pressRow to this._pressRow.bind(this)).
Moreover, some component (such as Text component) does not fill all the space of ListView row. So that onPress only works if you press right at text (it does not work if you press on the row location that does not have any text). So that it is useful to wrap with TouchableHighlight component.

Resources