undefined is not an object(evaluating this.props.navigator.push) - react-native

I have two page i.e sign in page and a payment page.
I am trying to navigate to payment page on tap on SignIn button, but i am getting error undefined is not an object(evaluating this.props.navigator.push)
The code is as below:
import React, {
StyleSheet,
Text,
View,
TextInput,
Component,
Alert,
Navigator
} from 'react-native';
var Button = require('react-native-button');
import Payments from '../payments'
class Signin extends Component{
onSubmitPressed(){
this.props.navigator.push({
title: 'secure Page',
component: <Payments/>
});
};
render() {
return(
<View style={styles.container}>
<View style={styles.Inputview}>
<TextInput id='user' style={styles.input}
placeholder={'Username'}
/>
<TextInput id='Password' secureTextEntry={true}
placeholder={'Password'}
onChangeText={password => this.setState({password})}
/>
</View>
<View >
<Button style={styles.Register}
onPress={(this.onSubmitPressed)}>
Sign In
</Button>
</View>
</View>
)
}
}
export default Signin
If any one let me know how to solve this issue??

You need to set up your Navigator and initial route as the entry point as opposed to a regular component. Try something like this:
(Also set up a working example here)
https://rnplay.org/apps/iKx2_g
class App extends Component {
renderScene (route, navigator) {
return <route.component navigator={navigator} />
}
render() {
return (
<Navigator
style={styles.container}
renderScene={this.renderScene.bind(this)}
initialRoute={{component: SignIn}}
/>
);
}
}
class SignIn extends Component {
_navigate () {
this.props.navigator.push({
component: Payments
})
}
render () {
return (
<View>
<Text>Hello from SignIn</Text>
<Button onPress={this._navigate.bind(this)} />
</View>
)
}
}
class Payments extends Component {
render () {
return (
<Text>Hello from Payments</Text>
)
}
}

First you need to bind the this to the function onSubmitPressed. And make sure that you have passed navigator object to this component on the renderScene function of the navigator.
// binding this to onSubmitPressed
<Button style={styles.Register}
onPress={this.onSubmitPressed.bind(this)}
>
Sign In
</Button>
// binding this to on SubmitPressed using arrow function
<Button style={styles.Register}
onPress={() => this.onSubmitPressed()}
>
Sign In
</Button>

Related

Passing Navigation to a Function Component

This Is My Home Page Code:
import React from "react";
//More Imports
export default class Home extends React.Component {
//Some Code
render() {
const { navigation } = this.props;
return (
<ScrollView>
//Some Code
<View style={styles.barContainer}>
<Button
title="Add Lesson"
onPress={() => navigation.navigate("ThisLesson")}
/>
</View>
//Some Code
{ScrollViewWithCards}
//Some Code
</ScrollView>
);
}
}
const styles = StyleSheet.create({
//Some Style
});
const cards = [
{
day: "3",
month: "Jan",
numberOfPeople: "4",
time: "17:00-18:00",
title: "Dance Class",
image: require("../../../assets/images/image1.jpeg"),
},
//More Cards...
];
const ScrollViewWithCards = (
<ScrollView>
{cards.map((card, index) => (
<View key={index} style={styles.cardContainer}>
<TouchableOpacity
onPress={() =>
navigation.navigate("ThisLesson", {
image: card.image,
day: card.day,
month: card.month,
time: card.time,
title: card.title,
numberOfPeople: card.numberOfPeople,
})
}
>
<HomeCard
image={card.image}
day={card.day}
month={card.month}
time={card.time}
title={card.title}
numberOfPeople={card.numberOfPeople}
/>
</TouchableOpacity>
</View>
))}
</ScrollView>
);
I'm mapping through an array of static data and rendering cards unto the screen
I made the cards pressable so that they take me to another page,
when I click the card it Returns an error:Reference Error: Can't find variable: navigation
But the Button Above the Cards Works Just Fine
What Am I Doing Wrong?
I tried the useNavigation Hook but it didn't work either
Update
This is my HomeCard component:
import React from "react";
//More Imports
const HomeCard = (props) => {
return (
<View style={styles.container}>
//Some Code
</View>
);
};
export default HomeCard;
const styles = StyleSheet.create({
//Some Style
});
const smallAvatars = [
//Some Array
];
I passed {navigation} to ScrollViewWithCards like so:
const ScrollViewWithCards =({navigation})=>()
but now I'm Getting another Error TypeError: undefined is not an object (evaluating 'navigation.navigate')
Solution
The Solution for this Problem is to transform ScrollViewWithCards to a function component, then pass props to it and add return:
const ScrollViewWithCards = (props) => {
return (
<ScrollView>
{cards.map((card, index) => (
<View key={index} style={styles.cardContainer}>
<TouchableOpacity
onPress={() =>
props.navigation.navigate("ThisLesson", {
image: card.image,
day: card.day,
month: card.month,
time: card.time,
title: card.title,
numberOfPeople: card.numberOfPeople,
})
}
>
<HomeCard
image={card.image}
day={card.day}
month={card.month}
time={card.time}
title={card.title}
numberOfPeople={card.numberOfPeople}
/>
</TouchableOpacity>
</View>
))}
</ScrollView>
);
};
and then in the main render:
<ScrollViewWithCards navigation={this.props.navigation} />
You are setting the const navigation inside the render function, and it wont be accessible inside other functions, so you have to use
this.props.navigation.navigate
Then you can simply do
const ScrollViewWithCards =()=> (
<ScrollView>
{cards.map((card, index) => (
<View key={index} style={styles.cardContainer}>
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate("ThisLesson", {
image: card.image,
day: card.day,
month: card.month,
time: card.time,
title: card.title,
numberOfPeople: card.numberOfPeople,
})
}
>
<HomeCard
image={card.image}
day={card.day}
month={card.month}
time={card.time}
title={card.title}
numberOfPeople={card.numberOfPeople}
/>
</TouchableOpacity>
</View>
))}
</ScrollView>
);
In the routing section, you need to mention the both component like this,
<Stack.Screen name="<your component name>" component={your component class} />
please don't forget to import the files at the above.
and then you can use the navigation props like,
this.props.navigation //for class component
props.navigation //for functional component
or if you have parent child relation in your compoent try this one:
<YOUR_COMPONENT navigation={props.navigation}/> // functional component
<YOUR_COMPONENT navigation={this.props.navigation}/> // class component

Use modal to take user checkbox input and return data back to parent component

I have a Newevent class component which takes several user inputs. One of them is an array of user ids called access list and the rest is text input. Here is the code I am thinking about:
export default class NewEvent extends React.Component {
state = {
name: '',
access_list: [],
modalVisible: false
};
triggerModal() {
this.setState(prevState => {
return {
display: true
}
});
}
render() {
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder='Name'
autoCapitalize="none"
placeholderTextColor='white'
onChangeText={val => this.onChangeText('name', val)}
/>
<Button
onPress = { () => this.triggerModal() }
title = "Open Modal"
color = "orange">
</Button>
<DisplayModal
visible={this.state.modalVisible}
/>
<Button
title='Save'
onPress={this.save}
/>
</View>
)
}
}
In DisplayModal.js, it is a function component to display a series of checkbox allowing user to check which user he wants to include in access list:
import React from 'react'
import { Modal, View, Image, Text, StyleSheet } from 'react-native';
import { CheckBox } from 'react-native-elements'
const DisplayModal = (props) => (
<Modal visible={ props.display } animationType = "slide"
onRequestClose={ () => console.log('closed') }>>
<View>
<CheckBox
title='Click Here1'
checked={this.state.checked}
/>
<CheckBox
title='Click Here2'
checked={this.state.checked}
/>
</View>
</Modal>
)
Any recommendation about constructing DisplayModal.js to return the user's selection?
I'm not sure about the problem but I think that you want to send states from DisplayModal to Newsevent for that purpose at least there are two methods:
1- Using redux which is a little(or too) complicated. you can read the documentation.
2- use a props which is a function that returns data from the child component to the parent.
for example:
export class DisplayModal extends Component {
state = {
item1: false,
item2: false
};
_updateState = item => {
this.setState({ item: !this.state[item] });
// use the getState props to get child state
return this.props.getState(this.state);
};
render() {
return (
<Modal
visible={props.display}
animationType="slide"
onRequestClose={() => console.log("closed")}
>
>
<View>
<CheckBox
title="Click Here1"
checked={this.state.checked}
onPress={() => this._updateState("item1")}
/>
<CheckBox
title="Click Here2"
checked={this.state.checked}
onPress={() => this._updateState("item2")}
/>
</View>
</Modal>
);
}
}
and use the getState props to get user's selections:
<DisplayModal getState={(items)=> this.setState({userSelections:items}) />
after each action on DisplayModal i.e on checkbox press, _updateState call the function the function in props and in your example, the function gets data from the child and update the parent state.

How to access navigation outside main component?

I've been working with the default tabs project created with create-react-native-app.
So I created my own screen where this.props.navigation is accessible in the main (export default class) component. It works fine to do navigate('Search') from the button titled 'nav default'.
However, after many tries, I couldn't navigate from either the button in the headerRight or in my custom component MyComponent.
How do I change my alerts to instead do navigate('Search') like the main component?
import React from 'react';
import { Button, Dimensions, ScrollView, StyleSheet, Text, View } from 'react-native';
class MyComponent extends React.Component {
// i wish i could navigate from here
render() {
//const { navigate } = this.props.navigation; // this causes TypeError undefined is not an object (evaluating this.props.navigation.navigate)
return (
<View>
<Button title="nav from component" onPress={() => alert('This should navigate, not alert')} color="red" />
</View>
);
}
}
export default class MyScreen extends React.Component {
// i wish i could navigate from here too
static navigationOptions = {
title: 'Test',
headerRight: (
//<Button onPress={() =>navigate('Search')} /> // how do I achieve this?
<Button title="nav from header" onPress={() => alert('This should navigate, not alert')} />
),
};
render() {
const { navigate } = this.props.navigation;
return (
<ScrollView style={styles.container}>
<Button onPress={() =>navigate('Search')} title="nav default" />
<MyComponent />
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 15,
backgroundColor: '#fff',
},
});
There are two different problems. First, navigation is only passed as a prop to the components that are navigation screens. So, to access it from other components, such as your MyComponent, you have to pass it through props <MyComponent navigation={navigation} /> and then you can use this.props.navigation.navigate inside it. You can also use the withNavigation higher order component, but in that case the first approach is better.
The other problem is, if you want to access the navigation prop in navigationOptions, you should define it as a function, and not as an object. The implementation would be something like this:
static navigationOptions = ({ navigation }) => ({
title: 'Test',
headerRight: (
<Button onPress={() =>navigation.navigate('Search')} />
),
});

error: "undefined is not an object(evaluating 'this,props.navigation.navigate')" In React Native

Getting errors when navigating one page to other page in React Native.
error:
undefined is not an object(evaluating 'this,props.navigation.navigate')
code:
import { StackNavigator,NavigationActions } from "react-navigation";
const Navigation = StackNavigator({
Home : {
screen : Home
},
})
export default class App extends React.Component {
submit = () => {
this.props.navigation.navigate('Home');
}
render() {
return (
<View style={styles.container}>
<Text>Enter Log</Text>
<TextInput style={styles.input}
multiline={true}
underlineColorAndroid="transparent"
placeholder="Enter Log"
placeholderTextColor="#9a73ef"
autoCapitalize="none"
onChangeText={this.handlePassword} />
<TouchableOpacity style={styles.submitButton} onPress={() => submit } >
<Text style={styles.submitButtonText}> Submit </Text>
</TouchableOpacity>
</View>
);
}
}
}
You have to bind your method:
import { StackNavigator,NavigationActions } from "react-navigation";
const Navigation = StackNavigator({
Home : {
screen : Home
},
})
export default class App extends React.Component {
constructor(props) {
super(props);
this.submit = this.submit.bind(this);
}
render() {
return (
<View style={styles.container}>
<Text>Enter Log</Text>
<TextInput style={styles.input}
multiline={true}
underlineColorAndroid="transparent"
placeholder="Enter Log"
placeholderTextColor="#9a73ef"
autoCapitalize="none"
onChangeText={this.handlePassword} />
<TouchableOpacity style={styles.submitButton} onPress={this.submit} >
<Text style={styles.submitButtonText}> Submit </Text>
</TouchableOpacity>
</View>
);
}
submit() {
this.props.navigation.navigate('Home');
}
}
Explanation: Binding context when calling ES6 method. How to access object from within method called as callback?
Try changing your onPress value to this:
onPress={this.submit}
Also, I don't see you importing your Home component to where you assign it as a screen.

React Native and Drawer : undefined is not an object navigator

I want to set up a sidebar menu with Drawer (Native Base).
I have a App.js :
export default class ReactProject extends Component {
renderScene (route, navigator) {
return <route.component navigator={navigator} />
}
render() {
return (
<Navigator
style={styles.container}
renderScene={this.renderScene.bind(this)}
initialRoute={{component: Home}}
/>
);
}
}
A Home.js with the drawer :
export default class Home extends Component {
render() {
return (
<Drawer
ref={(ref) => { this._drawer = ref; }}
content={<SideBar />} navigator={this.props.navigator}>
<Container>
</Container>
</Drawer>
);
}
}
And sidebar.js which is loaded into the drawer :
export default class SideBar extends Component {
constructor(props) {
super(props);
}
redirect(routeName){
this.props.navigator.push({
component: routeName
});
}
render() {
return (
<Content style={styles.sidebar}>
<ListItem button >
<Text>Home</Text>
</ListItem>
<ListItem button >
<Text>Test</Text>
</ListItem>
<ListItem button onPress={this.redirect.bind('Blank')}>
<Text>Blank Page</Text>
</ListItem>
</Content>
);
}
}
But when I click i have this error:
Undefined is not an object (evaluating 'this.props.navigator.push')
I do not have this problem when the button is in the page but only in the sidebar.js
Could someone help me?
thank you,
Thomas.
I think you have to change little bit code of your Home.js as per mentioned below:
render() {
return (
<Drawer
ref={(ref) => { this._drawer = ref; }}
content={<SideBar navigator={this.props.navigator} />}
<Container>
</Container>
</Drawer>
);
And add this lines of code in your sidebar.js file:
static propTypes = {
navigator: React.PropTypes.object,
}