can not read property navigate of undefined - react-native

I am mapping array to component.
{this.state.forms.map((data)=><Box data={data} />)}
and the code for component Box is
import React,{Component} from 'react'
import {View,Text,ScrollView,Image,Button,StyleSheet,AsyncStorage} from 'react-native'
class Login extends Component{
constructor(props){
super(props)
this.state = {
forms:[],
}
this.onSetCompany = this.onSetCompany.bind(this)
}
onSetCompany(data){
console.log(data)
// AsyncStorage.setItem('Company',data);
this.props.navigation.navigate('CompanyDeatails')
}
render(){
return(
<View style={style.container}>
{console.log(this.props.data)}
<View style={style.box}>
<View style={style.box1}>
<Text style={style.row2}>{this.props.data.CompanyName} bkb</Text>
</View>
<View style={style.box3}>
<Text style={style.row2}>{this.props.data.LastDate} </Text>
</View>
</View>
<View style={style.buttonBox}>
<View style={style.button}>
<Button color="#6d5d17" title="Fill" onPress={()=>this.props.navigation.navigate('CompanyDeatails')}></Button>
</View>
</View>
</View>
)
}
}
export default Login
var style = StyleSheet.create({
.....
})
and my Routes
export default class App extends Component{
render(){
return(
<Links />
)
}
}
const Links = DrawerNavigator({.....,
CompanyDeatails:{screen:CompanyDeatails},
....,
},{contentComponent:props => <Slider {...props}/>
})
When i Map array to Box then navigation in that box is not working.I have working navigation to which are working on my rest of app but not in this particular component.
Like
in login.js, I have this.props.navigation.navigate('C1')
Which is working but when I paste same line in Box component it throw error.
Can not read property navigate of undefined

If Box component is not part of navigator then, you should wrap it within withNavigation function inorder to access the navigation object. Take a look at the doc here
Consider the following example
import React from 'react';
import { withNavigation } from 'react-navigation';
class Box extends React.Component {
...
render() {
...
}
}
export default withNavigation(Box);
Now, within the Box component, you can access this.props.navigation.navigate function.
Hope this will help!

Related

Navigation.getParam is undefined while trying to pass function as parameter

I'm trying to use a function from my Main component in my details component which I user react navigation to navigate to and I want to save some changes in detail screen in my main component
//Main.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from 'react-native'
import Note from './Note'
import { createStackNavigator, createAppContainer } from "react-navigation";
import Details from './Details';
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: ''
};
}
render() {
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
goToDetailPage= {() => this.goToNoteDetail(key)}
/>
});
const { navigation } = this.props;
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details saveEdit={this.saveEdit} />
</View>
);
}
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
selectedTask: this.state.noteArray[key],
saveEdit: this.saveEdit
});
}
saveEdit = (editedTask,dueDate) => {
this.state.noteArray.push({
'creationDate': editedTask['creationDate'],
'taskName': editedTask['taskName'],
'dueDate': dueDate
});
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
this.setState({noteArray:this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
}
Then I try to use it as prop in my Detail.js
import React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
Button,
TouchableOpacity,
} from 'react-native'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Details extends React.Component {
constructor(props){
super(props);
this.state = {
dueDate = ''
}
}
static navigationOptions = {
headerStyle: {
backgroundColor: '#f4511e',
},
};
componentDidMount = () => {
this.getUserTasks()
}
render() {
const { navigation } = this.props;
const selectedTask = navigation.getParam('selectedTask', 'task');
var { saveEdit} = this.props;
return(
<View key={this.props.keyval} style={styles.container}>
<View style = { styles.info}>
<Text style= {styles.labelStyle}> Due date:
</Text>
<TextInput
onChangeText={(dueData) => this.setState({dueData})}
style={styles.textInput}
placeholder= {selectedTask['dueDate']}
placeholderTextColor='gray'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)} style={styles.saveButton}>
<Text style={styles.saveButtonText}> save </Text>
</TouchableOpacity>
</View>
);
}
}
I searched a lot to find the solution and I tried many of them but get different undefined errors. This is not what I did in the first place but when I search I found this solution here. And I know it causes lots of issues.
I want to know how can I manage to access to main method from details and pass parameters to it or how can I manage to use main props in my details component
If you are using react-navigation 5, params is no longer under the navigation object but under route object. This is the link to the sample code:
https://reactnavigation.org/docs/params
Solution
<Details saveEdit={this.saveEdit} />
to
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
render() {
return(
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<Details navigation={this.props.navigation} saveEdit={this.saveEdit} />
</View>
);
}
Why?
You are using your Details component in Main screen. So you need to give navigation to Details's props from your Main to use navigation props in Details component.
Because your Details component is not the screen component registered in your navigator(router).
I tried to run your code on my machine but it seems you have too many syntax error in your code (maybe because of copy pasta?)
but it seems you should change
<TouchableOpacity onPress={this.props.saveEdit(selectedTask, this.state.dueDate)}
in Detals.js to
<TouchableOpacity onPress={this.props.navigation.getParams('saveEdit')(selectedTask, this.state.dueDate)}
for clarification this worked for me
in MainPage.js
_test(){
console.log('test');
}
.
.
.
<ActionButton
buttonColor="rgba(231,76,60,1)"
onPress={() => NavigationService.navigate('AddNewSession', {test: this._test})}>
</ActionButton>
and in AddNewSession.js
componentDidMount()
let test = this.props.navigation.getParam('test');
test();
}
There are many mistakes within your codes. First of all you are importing the navigation build-in function {createStackNavigator} in all your files, Main.js and Details.js :
import { createStackNavigator, createAppContainer } from
"react-navigation";
That make me think that you didn't know how the stack navigation or navigation in general functions in react native. You should have a file that handles your routes configuration, let call it MyNavigation.js and then define the routes 'Main' and 'details' in MyNavigations,js. It's only inside MyNavigation.js that you can import "createStackNavigator". Then you will define your functions to move between the screens "Main" and "detail". Those functions will be passed as props to the routes when moving between one another. The overall action wihtin MyNavigation.js will look like:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import { NavigationContainer } from '#react-navigation/native';
import Main from './Main';
import Detail from './Detail';
const Stack = createStackNavigator();
function goToDetailFromMainScreen(){
return(this.props.navigation.navigate('switch2'));
}
function DetailSaves(){
return(//your code here to save details);
}
//Here you pass the functions to Main Component to handele Detail componets
's actions
function switch1(){
return(<Main GoToDetails={() => this.goTodetailFromMainScreen()} paramsForDetailActions={() => this.detailSaves()} />)
}
function switch2(){
return(<Details />)
}
export default function MyNavigation() {
return(
<NavigationContainer>
<Stack.Navigator initialRouteName='switch1'>
<Stack.Screen name='switch1' options={{header:()=>null}} component={Main} />
<Stack.Screen name='switch2' options={{headerTitle:"Detail"}} component={Detail} />
</Stack.Navigator>
</NavigationContainer>
)
}
Now inside Main.js you check the props functions passed to it from MyNavigation.js:
// Main.js
constructor(props){
super(props);
}
goToDetails = () => {
this.props.onPress?.();
}
paramsForDetailActions= () => {
this.props.onPress?.();
}

How to link mapStateToProps to two classes in the same React Native component

I have two classes in my react native component the first es without export so it's just a class the second is with export default. And then have mapStateToProps it's linked to the second class and it works fine but now I want to link the first class also because this.props.dipatch is not working . Have you any solution? Here is my code :
import React, { Component } from 'react';
import {
TouchableOpacity ,
View,
BackHandler,
Image,
Text,
Button,
Platform,
} from 'react-native';
import {connect } from 'react-redux'
class HeaderBarWebView extends Component{
constructor(props){
super(props);
}
goCamera(){
this.props.dispatch(changeCurrentPage("camera"))
}
render(){
return(
<View>
<TouchableOpacity style={{justifyContent:'center',display: 'flex'}}
onPress={this.goCamera}>
<Image
style={{tintColor:"white" , height:30,
width:30,marginRight:20}}
source={require('../resource/img/camera.png')}
/>
</TouchableOpacity>
</View>
)}}
class WebviewApp extends Component{
constructor(props)
{
this.state={}
this.goCamera= this.goCamera.bind(this)
goCamera(){
this.props.dispatch(changeCurrentPage("camera"))
}
render()
{
return(
<View style={{flex:1,width:"100%"}}>
<Button title="Press me" onPress={this.goCamera}></Button>
<CustomWebView
...........................
/>
</View>
);
}
}
const mapStateToProps = state => ({
page:state.router.page,
})
const WebviewAp = connect(mapStateToProps)(WebviewApp)
export default WebviewAp
You can also connect the first class just like second class
connect(mapStateToProps)(HeaderBarWebView);
const WebviewAp = connect(mapStateToProps)(WebviewApp);
export default WebviewAp;
But the batter way you should create new files for all separate component and use with import and export logic.

undefined is not an object (evaluating 'this.props.dispatch')

i have this React native component that contains two classes the first has a button that i want it to redirect me to another page it doesn't redirect anything it's just dispatching error . When i try the same function of redirection with the second class it works . Where is the problem please ?
import React, { Component } from 'react';
import {
TouchableOpacity ,
View,
BackHandler,
Image,
Text,
Button,
Platform,
ActivityIndicator
} from 'react-native';
import {connect } from 'react-redux'
class HeaderBarWebView extends Component{
constructor(props){
super(props);
}
goCamera(){
this.props.dispatch(changeCurrentPage("camera"))
}
render(){
return(
<View>
<TouchableOpacity style={{justifyContent:'center',display: 'flex'}}
onPress={this.goCamera}>
<Image
style={{tintColor:"white" , height:30,
width:30,marginRight:20}}
source={require('../resource/img/camera.png')}
/>
</TouchableOpacity>
</View>
)}}
class WebviewApp extends Component{
constructor(props)
{
this.state={}
this.goCamera= this.goCamera.bind(this)
goCamera(){
this.props.dispatch(changeCurrentPage("camera"))
}
render()
{
return(
<View style={{flex:1,width:"100%"}}>
<Button title="Press me" onPress={this.goCamera}></Button>
<CustomWebView
...........................
/>
</View>
);
}
}
const mapStateToProps = state => ({
page:state.router.page,
camera : state.router.camera
})
const WebviewAp = connect(mapStateToProps)(WebviewApp,HeaderBarWebView)
export default WebviewAp
Here is the error shown
You need to bind goCamera function with "this", in constructor;
constructor(props){
super(props);
this.goCamera = this.goCamera.bind(this);
}

How to pass children to react native ViewPager?

I'm quite new to react-native. Here Card is a view component having nothing special but text view with dimensions as flex: 1 I've my App.js as:
export default class App extends React.Component {
constructor(props: props){
super(props);
this.state = {
};
}
render() {
return (
<View style={styles.container}>
<ViewPager style={styles.pager} children={Card,Card,Card} count={3} height={100} width={100} selectedIndex={0} initialPage={0}>
</ViewPager>
</View>
);
}
}
I'm using the F8 app ViewPager which is made for both ViewPager & ScrollView for Android & iOS respectively. Which is as here (not inserting code here to keep it clean): ViewPager Component In F8 App
So what I need to know is how to pass a children to the ViewPager from my App.js
I'm not sure this is what you're looking for or what? Hope it will help you for some idea.
App.js passing value as View and Text
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<ViewPager style={styles.pager}>
// Children Array or any View as you prefer //
<Card>
<View>
<Text>Hello</Text>
</View>
</Card>
/////// End Block /////
</ViewPager>
</View>
);
}
}
ViewPager.js get value as props from App.js
export default class ViewPager extends React.Component {
render(){
return(
<View>
// these all props that pass from APP component
{this.props.children}
</View>
);
}
}

How to use onPress on a custom component?

Let's assume I have this custom component:
export default class Button extends Component {
render(){
return(
<TouchOpacity>
<Text> Button </Text>
</TouchOpacity>
)
}
}
And I use it in a parent component like this :
export default class MainPage extends Component {
render(){
return(
<Button onPress={ this.doSomething }></Button>
)
}
}
For some reason (unknown to me at least) this onPress even won't happen.
I'm pretty new to react-native btw. I believe I must find a way to enable this kind of event handling.
Is it possible to get a small example how to achieve that based on my examples above ?
So, just found out how to handle this.
export default class Button extends Component {
constructor(props){
super(props)
}
render(){
return(
<TouchableOpacity
onPress={this.props.onPress}
>
<Text> Button </Text>
</TouchableOpacity>
)
}
}
and
export default class MainPage extends Component {
render(){
return(
<Button onPress={ this.doSomething }></Button>
)
}
}
Long story short: since the onPress I'm passing is a prop in the MainPage, I'm passing it a function (this.doSomething) which later on is activated in Button's onPress.
Nick's answer is right.Along with that if you want to call separate function for both child and parent component then you can use onPressOut. This will help to manage state of componant
export default class Button extends Component {
constructor(props){
super(props)
}
onClickListen = () => {
if (this.state.isSelected === false) {
this.setState({isSelected:true});
isSelectedPass=true;
}
else {
this.setState({isSelected:false});
isSelectedPass=false;
}
}
render(){
return(
<TouchableOpacity
onPress={this.props.onPress} onPressOut={this.onClickListen}
>
<Text> Button </Text>
</TouchableOpacity>
)
}
}
export default class MainPage extends Component {
render(){
return(
<Button onPress={ ()=>this.doSomething }></Button>
)
}
}