Can't create function outside render in react native 0.61.1 - reactjs

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

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 :

Calling a children method of a functional component from parent

I am not using class, I'd like to learn how to do it manually. I am dealing with login screen.
https://snack.expo.io/#ericsia/call-function-from-child-component
If you want to show me your code, you need to save and share the link. So I wanted a functional component for display textbox (assume ChildComponent as the function name, so export ChildComponent).
So in Parent/Screen1 I have something like this right?
import * as React from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import ChildComponent from './components/ChildComponent';
export default function App() {
function checkSuccess()
{
// call helloWorld from here
}
return (
<View style={styles.container}>
<ChildComponent />
<TouchableOpacity style={styles.button}
onPress={ checkSuccess } >
<Text>helloWorld ChildComponent</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
button: {
alignItems: "center",
backgroundColor: "#DDDDDD",
padding: 10
},
});
so if the result is invalid right, I wanted to display a tiny red error message.
something like this
My approach is if I can call a function from the ChildComponent then I may still solve it.
I googled it and most of the solution provided is for class.
I tried useEffect React.createRef useImperativeHandle but I didn't get it work.
for start, i am just trying to call the helloWorld()
import * as React from 'react';
import { TextInput , View, StyleSheet, Image } from 'react-native';
export default function ChildComponent() {
function helloWorld()
{
alert("Hello World");
}
return (<TextInput placeholder="Try to call helloWorld from App.js"/>);
}
Another question, if I have a textbox in my ChildComponent how do I retrieve the text/value from parent?
The Easy Way: Passing Props
You can move the helloWorld function up to the parent component and pass it down to the child as a prop. That way both components can call it. I recommend using an arrow function when you are going to be passing around a function, though it doesn't matter in this case.
Parent
export default function App() {
const helloWorld = () => {
alert('Hello World');
}
const checkSuccess = () => {
helloWorld();
}
return (
<View style={styles.container}>
<ChildComponent helloWorld={helloWorld} />
<TouchableOpacity style={styles.button} onPress={checkSuccess}>
<Text>helloWorld ChildComponent</Text>
</TouchableOpacity>
</View>
);
}
Child
const ChildComponent = ({ helloWorld }) => {
// could do anything with helloWorld here
return <TextInput placeholder="Try to call helloWorld from App.js" />;
};
The Hard Way: Ref Forwarding
If you want to keep the function in the child component then you need to go through a lot of hoops. I do not recommend this approach.
You have to do all of these steps:
Create a ref object in the parent using useRef: const childRef = React.useRef();
Pass the ref to the child as a prop: <ChildComponent ref={childRef} />
Call the function on the current value of the child component ref, using ?. to avoid errors if .current has not yet been set: childRef.current?.helloWorld();
Accept the ref prop in the child by using forwardRef: React.forwardRef( (props, ref) => {
Expose the helloWorld function as an instance variable of the child component by using useImperativeHandle: React.useImperativeHandle(ref , () => ({helloWorld}));
Parent:
export default function App() {
const childRef = React.useRef();
function checkSuccess() {
childRef.current?.helloWorld();
}
return (
<View style={styles.container}>
<ChildComponent ref={childRef} />
<TouchableOpacity style={styles.button} onPress={checkSuccess}>
<Text>helloWorld ChildComponent</Text>
</TouchableOpacity>
</View>
);
}
Child:
const ChildComponent = React.forwardRef((props, ref) => {
function helloWorld() {
alert('Hello World');
}
React.useImperativeHandle(ref, () => ({ helloWorld }));
return <TextInput placeholder="Try to call helloWorld from App.js" />;
});
Edit: Expo Link

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

Touch handler not called with React Native

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

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