(React-Native) undefined is not an object (evaluating _'this.props.navigation.navigate') - reactjs

I'm still a novice with react. I want to make my sign In button create a new screen on the press. I've tried multiple attempts but I can't seem to get past this error:
What is it I'm doing wrong?
LoginForm.js:
import React, { Component } from 'react';
import { TextInput, Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Button, CardSection, Input, Spinner } from './common';
import Account from './screens/Account';
import SignUpForm from './SignUpForm';
class LoginForm extends Component {
render() {
return (
<View style={styles.container}>
<TextInput
placeholder="Username or email"
placeholderTextColor='white'
returnKeyType='next'
style={styles.input}
keyboardType="email-address"
onSubmitEditing={() => this.passwordInput.focus()}
/>
<TextInput
secureTextEntry //turns text into *** good for passwords
label="Password"
placeholder="password"
placeholderTextColor='white'
secureTextEntry
returnKeyType='go'
style={styles.input}
ref={(input) => this.passwordInput = input}
/>
<TouchableOpacity style={styles.buttonContainer}>
<Text style={styles.buttonText}>LOGIN</Text>
</TouchableOpacity>
<Text style={styles.textStyle}> Need help logging in?{'\n'}
or
</Text>
<View style={styles.divider} />
<TouchableOpacity
style={styles.buttonContainer}
onPress={() => this.props.navigation.navigate('SignUpForm')}
>
<Text style={styles.buttonText}>Sign Up</Text>
</TouchableOpacity>
</View>
);
}
}
export default LoginForm;
**Account.js:**
import React from 'react';
import { View, Image, TouchableOpacity, Text, TextInput } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Card, Button, Spinner, CardSection } from '../common';
import LoginForm from '../LoginForm';
class Account extends React.Component {
static navigationOptions = {
tabBarLabel: 'Account'
}
render() {
return (<View style={styles.containerStyle}>
<Card>
<View style={styles.logoContainer}>
<Image style={styles.logo} source= .
{require('../../Images/ShoeJackCityLogo.png')}/>
</View>
<View style={styles.formContainer}>
<LoginForm />
</View>
</Card>
</View>);
}
}
export default Account;
**SignUpForm.js:**
import React, { Component } from 'react';
import { TextInput, Text, View, StyleSheet, TouchableOpacity } from 'react-native';
import { Button, CardSection, Input, Spinner } from './common';
import router from '../../config/router';
class SignUpForm extends Component {
render() {
return (
<View style={styles.container}>
<TextInput
placeholder="Username or email"
placeholderTextColor='white'
returnKeyType='next'
style={styles.input}
keyboardType="email-address"
onSubmitEditing={() => this.EmailInput.focus()}
/>
<TextInput
placeholder="Email"
placeholderTextColor='white'
returnKeyType='next'
style={styles.input}
keyboardType="email-address"
onSubmitEditing={() => this.passwordInput.focus()}
/>
<TextInput
secureTextEntry //turns text into *** good for passwords
label="Password"
placeholder="password"
placeholderTextColor='white'
secureTextEntry
returnKeyType='go'
style={styles.input}
ref={(input) => this.passwordInput = input}
/>
<TouchableOpacity style={styles.buttonContainer}>
<Text style={styles.buttonText}>Register</Text>
</TouchableOpacity>
</View>
);
}
}
export default SignUp;
import React from 'react';
import { TabNavigator, StackNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
**Router.js**
import Tournaments from '../components/screens/Tournaments';
import Account from '../components/screens/Account';
import Artists from '../components/screens/Artists';
import Shop from '../components/screens/Shop';
import SignUpForm from '../components/SignUpForm';
export const AccountStack = StackNavigator({
Account: {
screen: Account,
navigationOptions: {
title: 'Account',
headerBackTitle: null,
},
SignUpForm: {
screen: SignUpForm,
navigationOptions: {
title: 'Register'
}
},
Ignore this: jsksjkjdkfjkdfkjkdjskfjskjfjksjkjfkjsjfkjskfsjfjsjfksjfjfskfjkskjfjkjskjfjjksfjksfjkfjkfjssfjkfksskjfjsfjk

<LoginForm />
I don't see that you are passing any props into LoginForm which expects this.props.navigation in onPress.

I think you have some confusion related to how the navigation stack works in react-native. So, essentially there are two ways of navigating to a screen.
By declaring it in the StackNavigator class, you are providing the <LoginForm/> component the required navigation object. Once, declared you'll need to navigate to the login form from any screen - like - this.props.navigation.navigate('LoginForm'). Note - you'll be only be able to navigate from either <Account/> or <Signup/> because those two screens currently posses the navigation object in their scope. Now, once you have navigated to the login form component you'll essentially have the navigation object in scope, and your undefined error will go away.
If you decide not to declare the <LoginForm/> screen in the StackNavigator class, you'll need to pass the navigation object explicitly as props to the component, like - <LoginForm navigation={this.props.navigation} />. So, that whenever you render this component, you'll be able to fetch the navigation prop the same way you are using it.
Hope it clears out things for you :)

Its hard for me to tell without seeing where you declared your stafcknavigation if you didn't then this is the link to learn how http://react-navigation%20stack%20navigator%20custom%20header
otherwhise you are probably not passing the navigation method to a nested component
here is a link to see how to do that navigation between component in react native

Your LoginForm component doesn't have 'this.props.navigate' since it is not registered with any navigator, you are calling that component inside your 'Account' component which is registered to navigator.
If you want to navigate inside 'LoginForm' you need to pass 'this.props.navigation' like
<LoginForm myNavigation = {this.props.navigation} />
And inside that onPress in LoginForm use
onPress = { ()=> this.props.myNavigation.navigate('SignUpForm) }

Related

Anybody know why this doesn't work if its writen like the react navigation docs?

This is the btn that 'controls' the navigation.
It loads the first Stack, Home, but when I press the touchable opacity to go QnScreen it drops an error: undefined is not an object (evaluating 'navigation.navigate').
I try it all, I'm falling into depression lol.
import * as React from 'react';
import { LinearGradient } from "expo-linear-gradient";
import { StyleSheet, Text, TouchableOpacity, Image } from "react-native";
export default function DocCard( { navigation } ){
return(
<TouchableOpacity
style={styles.container}
onPress={()=>{
navigation.navigate('QnScreen')
}}
>
<LinearGradient
style={styles.linearGradient}
colors={['#4822E4','transparent']}
start={{x:0, y:0}}
end={{x:1, y:1}}>
<Text style={styles.title}>Create new Doc.</Text>
<Image
style={styles.icon}
source={require('../../img/HomeScreen/doc_icon.png')}
/>
</LinearGradient>
</TouchableOpacity>
);
}
And this is the MainStack:
import { NavigationContainer, useNavigation } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import QnScreen from '../screens/QnScreen';
import Home from '../screens/Home';
import React from 'react';
const Stack = createNativeStackNavigator();
export default function MainStack(){
return(
<NavigationContainer>
<Stack.Navigator
screenOptions={{
headerShown: false
}}
>
<Stack.Screen
name='Home'
component={Home}
/>
<Stack.Screen
name='QnScreen'
component={QnScreen}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
I'm using Expo with typescript
First off, you'll need to have that navigation.navigate() call include a parameter that states which screen/screen-stack you want to navigate to. It doesn't look like that's your main issue though.
I can't tell from just the code you've posted, but judging from the 'navigation' object being undefined, it's most likely that your DocCard component is not a child of your Navigator. Where is DocCard in your component tree? Is it inside QnScreen or Home? Cause that's where it should be.
Then you'll need to receive the 'navigation' prop from one of your screens. And pass it as a prop to DocCard to be used. 'Navigation' and 'route' props are only automatically passed to screens.
I solve it!!!
The solution was using the useNavigation hook inside the component.
import { useNavigation } from "#react-navigation/native";
import { LinearGradient } from "expo-linear-gradient";
import { StyleSheet, Text, TouchableOpacity, Image } from "react-native";
export default function DocCard(){
const navigation = useNavigation();
return(
<TouchableOpacity
style={styles.container}
onPress={()=>{
navigation.navigate('QnScreen');
}}
>
<LinearGradient
style={styles.linearGradient}
colors={['#4822E4','transparent']}
start={{x:0, y:0}}
end={{x:1, y:1}}>
<Text style={styles.title}>Crear nuevo documento de consentimiento informado.</Text>
<Image
style={styles.icon}
source={require('../../img/HomeScreen/doc_icon.png')}
/>
</LinearGradient>
</TouchableOpacity>
);
}
If anybody have this problem, there's the solution:)

[React Native, RN]TypeError: undefined is not an object (evaluating 'route.params')

import React, {useState, Component, useMemo} from 'react';
import { StyleSheet, Text, View, Button, TextInput, Image } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import AsyncStorage from '#react-native-async-storage/async-storage'
import { createStackNavigator } from '#react-navigation/stack';
const Stack = createStackNavigator();
function GameScreen({ navigation, route }){
const [name, setName] = useState('이화연');
return(
<View style={{paddingTop:10}}>
<View style={{flexDirection:"column"}}>
<Text style={text_st}>당신의 이름을 알려 주세요.</Text>
<TextInput style={input_st}
onChangeText={setName}
value={name}
maxLength={10}/>
<Button title="확인"
color= {EwhaGreen}
onPress={function(){navigation.navigate('1',
{ params: name } )}} />
</View>
</View>
);
};
function GameScreen_1({ navigation }, {route}){
var N = route.params.name
return(
<View style={{alignItems:'center', justifyContent:'center'}}>
<View style={{margin:5}}></View>
<div>
<Text>{N}, 일어나!</Text>
</div>
<Text>눈을 떠 보니 여기는...?</Text>
<View style={{margin:5}}></View>
<Image style={{width:500, height:500}} source={require('./assets/1.jpg')} />
<View style={{margin:10}}></View>
<Button title="이화여대?"
color= {EwhaGreen}
onPress={function(){navigation.navigate('2') }} />
</View>
);
};
I want to use const name in function GameScreen_1. But only thing I got is an error code 'TypeError: undefined is not an object (evaluating 'route.params')' Please help me. I spend many days to solve this problem.
It should be
function GameScreen_1({ navigation, route})
You have placed it inside another Curley brackets.
Your function body should look like that
function GameScreen_1({ route, navigation }){
Here the docs https://reactnavigation.org/docs/params/

this.props in component does not contain navigation property

I want to navigate from one screen to another by this.props.navigation.navigate('Second Screen') but property 'navigation' does not contain in the props. Get error:
Property 'navigation' does not exist on type 'Readonly<{}> & Readonly<{ children?: ReactNode; }>'
import React, { Component } from "react";
import styles from "./style";
import { Keyboard, Text, View, TextInput, TouchableWithoutFeedback, KeyboardAvoidingView } from 'react-native';
import { Button } from 'react-native-elements';
export default class SignInScreen extends Component {
render() {
return (
<KeyboardAvoidingView style={styles.containerView} behavior="padding">
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.loginScreenContainer}>
<View style={styles.loginFormView}>
<Text style={styles.logoText}>Book Market</Text>
<TextInput placeholder="Email" placeholderTextColor="#c4c3cb" style={styles.loginFormTextInput} />
<TextInput placeholder="Password" placeholderTextColor="#c4c3cb" style={styles.loginFormTextInput} secureTextEntry={true} />
<Button
buttonStyle={styles.loginButton}
onPress={this.props.navigation.navigate('Home')}
title="Login"
/>
</View>
</View>
</TouchableWithoutFeedback>
</KeyboardAvoidingView>
);
}
}
You can only access it through the parent element. Pass navigation as a prop to its children to use it
Eg:
<Child navigation={this.props.navigation} />
You can do what was already suggested, pass the navigation prop down to your target component
Ex:
<TargetComponent navigation={this.props.navigation} />
Or you can use withNavigation HOC from react-natigation.
Ex:
import {withNavigation} from 'react-navigation'
...
export default withNavigation(Child)
Hope it helps.
Okay, I find a solution. At first, I need to change extends of my class like
export default class SignInScreen extends Component<{navigation: any}>
Then change onPress action:
<Button
buttonStyle={styles.loginButton}
onPress={() => this.onSignInPress()}
title="Login"
/>
private onSignInPress() {
this.props.navigation.navigate('Home');
}
I know this is an old question, but since the problem of undefined navigation property still exists at least for those who use EXPO managed approach, I'll write my solution hopefully it'll save someone's day.
After searching for hours I found no way to fix this bug and find a way to add navigation property to this.props. Finally, I solved the problem by using NavigationContext in this way:
<NavigationContainer>
<NavigationContext.Provider>
<Stack.Navigator>
...
</Stack.Navigator>
</NavigationContext.Provider>
</NavigationContainer>
Then get the navigation in a consumer:
<NavigationContext.Consumer>
{navigation => {
return (
<Button onPress={() => this.onButtonPress(navigation)} />
);
}}
</NavigationContext.Consumer>
And finally:
onButtonPress(navigation) {
try {
navigation.navigate(RouteNames.FORGOTTEN_PASSWORD_SCREEN);
} catch (e) {
this.setState({ errors: [e.message] });
}
}

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;

React Native What I'm doing wrong here with constant

I'm trying to implement one functional component. Here I am doing below, But I'm getting error about props. Could someone help me.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
const TextField = () => {
return (
<Text> {this.props.title} </Text>
)
}
export default TextField;
// APP Component
import TextField from './Components/TextField'
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<TextField title= "Simple App"/>
</View>
);
}
}
The reason is this.props is not defined in a functional component. They receive the props as an argument.
Change your TextField to take argument props and use props.title
const TextField = (props) => {
return (
<Text> {props.title} </Text>
)
}

Resources