React Native Error undefined is not an object (evaluating 'navigation.push') - javascript

I want to navigate to List.js after I click the button in MainMenu.js file, but it always shows me this error:
TypeError: undefined is not an object (evaluating 'navigation.push')
This is my App.js file
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { List } from './List';
import { MainMenu } from './MainMenu';
export default function App() {
return (
<View style={styles.container}>
<Text>Open up App.js to stassrt working on your app!</Text>
<StatusBar style="auto" />
<MainMenu></MainMenu>
</View>
);
}
And this is my MainMenu.js file (I have the button in this file):
import React from 'react';
import { Text, Button, View, StyleSheet } from 'react-native';
import { ScreenContainer } from 'react-native-screens';
import { List } from './List';
import { useNavigation } from '#react-navigation/core';
export const MainMenu = ({navigation}) => (
<View>
<Text>Hello HOW ARE YsOU</Text>
<Button title="Click" onPress={() => navigation.push("List")}></Button>
</View>
);

In your MainMenu component, you are expecting an object with a key navigation as props. You are not passing any props to the MainMenu, however, and so the props are undefined, but you are expecting an object. To fix this, change the component to:
import React from 'react';
import { Text, Button, View, StyleSheet } from 'react-native';
import { ScreenContainer } from 'react-native-screens';
import { List } from './List';
import { useNavigation } from '#react-navigation/core';
export const MainMenu = () => {
const navigation = useNavigation()
return (
<View>
<Text>Hello HOW ARE YsOU</Text>
<Button title="Click" onPress={() => navigation.push("List")}>
</Button>
</View>
);
};
We are using the hook, instead of props.

I don't know how you implemented the stack navigator, but I think your App.js file should look like this:
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { List } from './List';
import { MainMenu } from './MainMenu';
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<>
<Stack.Screen name="Main Menu" component={MainMenu} />
<Stack.Screen name="List" component={List} />
</>
</Stack.Navigator>
</NavigationContainer>
);
}
And I think your MainMenu component should look like this:
import React from 'react';
import { Text, Button, View, StyleSheet } from 'react-native';
import { ScreenContainer } from 'react-native-screens';
import { List } from './List';
export const MainMenu = ({navigation}) => (
<View style={styles.container}>
<Text>Open up App.js to stassrt working on your app!</Text>
<StatusBar style="auto" />
<View>
<Text>Hello HOW ARE YsOU</Text>
<Button title="Click" onPress={() => navigation.navigate("List")</Button>
</View>
</View>

Related

How do I pass the selected value in the drop down picker to another page?

I have tried to pass the data that is selected in the drop down picker to another page via https://www.youtube.com/watch?v=C01CJlu7Q-I
First page
import { TouchableOpacity, StyleSheet, Text, View } from 'react-native'
import React from 'react'
import { auth } from '../firebase'
import { useNavigation } from '#react-navigation/core'
import { signOut } from 'firebase/auth'
import DropDownPicker from 'react-native-dropdown-picker'
import { useEffect, useState } from 'react'
const HomeScreen = () => {
const navigation = useNavigation()
const [open, setOpen] = useState(false);
const [value, setValue] = useState(null);
const [items, setItems] = useState([
{label: 'Japanese', value: 'J'},
{label: 'Korean', value: 'K'},
{label: 'Western', value: 'F'},
{label:'Indonesian', value:'I'},
{label: 'Taiwan', value: 'T'},
{label:'Chinese', value:'C'},
]);
const handleSignOut = async () =>{
try{
await signOut(auth)
console.log("Signed out successfully")
navigation.replace("Login")
}catch (error) {
console.log({error});
}
}
return (
<View style = {styles.container}>
<Text>Welcome {auth.currentUser?.email}</Text>
<Text></Text>
<Text>What cusine would you like to eat today?</Text>
<DropDownPicker
open={open}
value={value}
items={items}
setOpen={setOpen}
setValue={setValue}
setItems={setItems}
/>
<TouchableOpacity
onPress={() => navigation.navigate("SubScreen1", {paramKey:items})}
style = {styles.button}
>
<Text style = {styles.buttonText}>Search</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={handleSignOut}
style = {styles.button}
>
<Text style = {styles.buttonText}>Sign Out</Text>
</TouchableOpacity>
</View>
)
}
Another page where I am trying to pass the value to. Currently it is very simple but it cannot work
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
const SubScreen1 = (route) => {
return (
<View>
<Text>{route.params.paramkey}</Text>
</View>
)
}
export default SubScreen1
const styles = StyleSheet.create({})
My app.js
import { StatusBar } from 'expo-status-bar';
import React from 'react'
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import LoginScreen from './screens/LoginScreen';
import HomeScreen from './screens/HomeScreen';
import RegisterScreen from './screens/RegisterScreen';
import ForgetPasswordScreen from './screens/ForgetPasswordScreen';
import SubScreen1 from './screens/SubScreen1';
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen options= {{ headerShown : false }} name="Login" component={LoginScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Register" component={RegisterScreen} />
<Stack.Screen name="Forget Password" component={ForgetPasswordScreen} />
<Stack.Screen name="SubScreen1" component={SubScreen1} />
</Stack.Navigator>
</NavigationContainer>
);
}
But when i clicked the search button, it is not jumping to the next page. I assume its something wrong with the passing of the key. How do i fix this?
After editing, I encountered another error. This happens after I press the search button. How do i solve this?
I tried referring to this Moving values from one screen to another ERROR: undefined is not an object (evaluating 'route.params.message') but it doesnt work
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
const SubScreen1 = (route) => {
const { param1 } = route.params.paramKey
return (
<View>
<Text>{param1}</Text>
</View>
)
}
export default SubScreen1
const styles = StyleSheet.create({})
first log the value and see the response. you forgot the key of items...
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
const SubScreen1 = (route) => {
const { param1 } = route.params.paramKey
return (
<View>
<Text>{param1.items}</Text>
</View>
)
}
export default SubScreen1
const styles = StyleSheet.create({})

TypeError: _this.props.loginState is not a function

When the user presses the login button the Drawer.Navigation needs to change (I try to learn the basics so no form for the login needed). When I try to pass this action to App.js I get this Error:"TypeError: _this.props.loginState is not a function"
According to the errormessage the problem should be in this pice of code:
changeLoginState = () => {
this.props.loginState(true)
}
This is the code of App.js
import * as React from 'react';
import { getFocusedRouteNameFromRoute, NavigationContainer } from '#react-navigation/native';
import { createAppContainer } from "react-navigation";
import { RootNavigator } from './src/navigation/AppNavigator';
import { PropTypes } from 'react'
//navigation
import { createDrawerNavigator } from '#react-navigation/drawer'
import Account from './src/screens/account';
import Login from './src/screens/Login'
export default function App(){
let isLoggedIn = false
function changeLoginState(newState){
isLoggedIn = newState
}
const Drawer = createDrawerNavigator();
let d
let p
let l
if(isLoggedIn){
d = <Drawer.Screen name="Account" component={Account}/>
}else{
d = <Drawer.Screen name="Inloggen" component={Login} loginState={changeLoginState}/>
}
return(
<NavigationContainer>
<Drawer.Navigator initialRouteName="Home">
{d}
</Drawer.Navigator>
</NavigationContainer>
)
}
And this is the code of Login comoponent: Login.js
import * as React from 'react';
import { Component } from 'react';
import { View, Button, StyleSheet, TouchableOpacity} from 'react-native';
class Login extends Component {
constructor(props){
super(props)
}
changeLoginState = () => {
this.props.loginState(true)
}
render(){
return (
<View style={{display: 'flex', justifyContent:'center', alignItems:'center', height: '100vh'}}>
<TouchableOpacity style={{backgroundColor: 'red'}} onPress={ () => this.changeLoginState() }>Login</TouchableOpacity>
</View>
);
}
}
export default Login
I have seen a lot of similar questions but nothing worked.
If you have other remarks on my code, feel free to comment.
I thank you.
Use options to pass props to screen:
options={{ loginState: changeLoginState }}

Trying to access route.params in react native stack navigator v5

I am trying to access the props.route.params.data information from the react navigation route prop, however when I try to output it on the screen it just says TypeError: undefined is not an object(evaluating props.routes.params). I know I have correctly followed the path to that data object because I console.log it on the console and it outputs that data. However when I want to put put it on the user interface it gives me that error. Been searchong online but no one has the same issue, maybe because the way to get the params using react stack navigator v5 is by route.params, and v5 came outa couple of months ago. So I will post my code below along with the console.log screen, the error message, and also the object that I am picking from. Thank you!
// App.js
import 'react-native-gesture-handler';
import React from 'react';
import { View , StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import About from "./screens/About";
import Home from "./screens/Home";
import PokeDetails from "./screens/PokeDetails"
import { createStackNavigator } from '#react-navigation/stack';
const App =()=> {
const Stack = createStackNavigator();
return(
<View style={styles.container}>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={Home}/>
<Stack.Screen name="PokeDetails" component={PokeDetails}/>
<Stack.Screen name="About" component={About}/>
</Stack.Navigator>
</NavigationContainer>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1
}
})
export default App;
// Home.js
import React, { useState } from "react";
import { View, Text , Button, FlatList, ActivityIndicator, TouchableOpacity, Image } from "react-native";
import { GlobalStyles } from "../styles/GlobalStyles";
import PokeDetails from "./PokeDetails";
import { useRoute } from '#react-navigation/native';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
}
}
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/?limit=20`)
.then((res)=> res.json())
.then((response)=> {
this.setState({
isLoading: false,
dataSource: response.results,
})
console.log("RESPONSE",response)
console.log("RESPONSE.RESSSULTS",response.results)
})
}
render() {
const showIndicator = this.state.isLoading == true ? <ActivityIndicator size="large" color="#0000ff" /> : null;
return(
<View style={GlobalStyles.container}>
<View style={GlobalStyles.activityIndicator}>{showIndicator}</View>
<FlatList
keyExtractor={(item, index) => item.name}
numColumns={1}
data={this.state.dataSource}
renderItem={({item})=>
<TouchableOpacity onPress={()=> this.props.navigation.navigate('PokeDetails',
{data:"hello"})}>
<PokeDetails imageUrl={`https://projectpokemon.org/images/normal-sprite/${item.name}.gif`} name={item.name}/>
</TouchableOpacity>
}/>
<Button onPress={()=> this.props.navigation.navigate("About")} title="Go to about"/>
</View>
)
}
}
export default Home;
// PokeDetails.js
import React from "react";
import { View, Text , Image, Button} from "react-native";
import {GlobalStyles} from "../styles/GlobalStyles";
import { TouchableOpacity } from "react-native-gesture-handler";
import { useRoute } from '#react-navigation/native';
const PokeDetails =(props)=> {
console.log(props)
console.log(props.route.params.data, "PROPSSSSSSSSSSS");
return(
<View style={GlobalStyles.container}>
<Image source={{uri: props.imageUrl}} style={{height: 50, width: 50}}/>
<Text>{props.route.params.data}</Text>
</View>
)
}
export default PokeDetails;
You are getting the following error because you are pokedetails in your home screen, you can get the data props only if you navigate to pokedetails screen, the thing you can do something like this:
change your Home.js like this:
import React, { useState } from "react";
import { View, Text , Button, FlatList, ActivityIndicator, TouchableOpacity, Image } from "react-native";
import PokeDetails from "./Pokedetails";
import { useRoute } from '#react-navigation/native';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
}
}
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/?limit=20`)
.then((res)=> res.json())
.then((response)=> {
this.setState({
isLoading: false,
dataSource: response.results,
})
console.log("RESPONSE",response)
console.log("RESPONSE.RESSSULTS",response.results)
})
}
render() {
const showIndicator = this.state.isLoading == true ? <ActivityIndicator size="large" color="#0000ff" /> : null;
return(
<View>
<View>{showIndicator}</View>
<FlatList
keyExtractor={(item, index) => item.name}
numColumns={1}
data={this.state.dataSource}
renderItem={({item})=>
<TouchableOpacity onPress={()=> this.props.navigation.navigate('PokeDetails',
{data:"hello", imageUrl:`https://projectpokemon.org/images/normal-sprite/${item.name}.gif`})}>
<PokeDetails imageUrl={`https://projectpokemon.org/images/normal-sprite/${item.name}.gif`} name={item.name}/>
</TouchableOpacity>
}/>
<Button onPress={()=> this.props.navigation.navigate("About")} title="Go to about"/>
</View>
)
}
}
export default Home;
Here iam just passing imageUrl also for reference purpose.
change your pokedetails.js some thing like this:
import React from "react";
import { View, Text , Image, Button} from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler";
import { useRoute } from '#react-navigation/native';
const PokeDetails =(props)=> {
console.log("props is",props);
if(props.navigation == undefined)
{
return(
<View>
<Image source={{uri: props.imageUrl}} style={{height: 50, width: 50}}/>
<Text>{props.name}</Text>
</View>
)
}
else{
return(
<View>
<Image source={{uri: props.route.params.imageUrl}} style={{height: 50, width: 50}}/>
<Text>{props.route.params.data}</Text>
</View>
)
}
}
export default PokeDetails;
Here iam just adding a if condition to check whether the screen is loaded is navigated from another screen.
when the Homescreen loaded it will be something like this:
On clicking bulbassor you will be navigating to the pokedetails screen where here iam showing the details you are sending through navigation:
Hope this helps!

How to implement details screen that dynamically displays detail of pokemon when a user presses on a picture in react native?

So I have built a pokemon application that would display pokemon with their images and details. On the homescreen, I have it so that the first 20 pokemon are shown as a preview. Then if the user wants to learn more about the pokemon, they can press on the pokemon and it would bring the user to the "PokeDetails" screen. However, when I press on the pokemon, it brings me to the "PokeDetails" page but the page is blank. Except for the text that I explicitly render from the "PokeDetails" screen. I have the code for both screens below. Any help is appreciated. Thank you
//Home.js
import React, { useState } from "react";
import { View, Text , Button, FlatList, ActivityIndicator, TouchableOpacity, Image } from "react-native";
import { GlobalStyles } from "../styles/GlobalStyles";
import PokeDetails from "./PokeDetails";
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
}
}
componentDidMount() {
fetch(`https://pokeapi.co/api/v2/pokemon/?limit=20`)
.then((res)=> res.json())
.then((response)=> {
this.setState({
isLoading: false,
dataSource: response.results,
})
console.log("RESPONSE",response)
console.log("RESPONSE.RESSSULTS",response.results)
})
}
render() {
const showIndicator = this.state.isLoading == true ? <ActivityIndicator size="large" color="#0000ff" /> : null;
return(
<View style={GlobalStyles.container}>
<View style={GlobalStyles.activityIndicator}>{showIndicator}</View>
<FlatList
numColumns={1}
data={this.state.dataSource}
renderItem={({item})=>
<TouchableOpacity onPress={()=> this.props.navigation.navigate("PokeDetails", {item} )}>
<PokeDetails imageUrl={`https://projectpokemon.org/images/normal-sprite/${item.name}.gif`} name={item.name} item={item} />
</TouchableOpacity>
}/>
<Button onPress={()=> this.props.navigation.navigate("About")} title="Go to about"/>
</View>
)
}
}
export default Home;
// PokeDetails.js
import React from "react";
import { View, Text , Image, Button} from "react-native";
import {GlobalStyles} from "../styles/GlobalStyles";
import { TouchableOpacity } from "react-native-gesture-handler";
import { useRoute } from '#react-navigation/native';
const PokeDetails =({name, imageUrl, detail, route})=> {
return(
<View style={GlobalStyles.container}>
<Text>This text is written expilictly</Text>
<Text>{route.params.item}</Text>
</View>
)
}
export default PokeDetails;
// Root.js
import React from "react"
import { createStackNavigator } from "#react-navigation/stack";
import Home from "../screens/Home";
import PokeDetails from "../screens/PokeDetails";
import { NavigationContainer } from '#react-navigation/native';
const Root =() => {
const Stack = createStackNavigator();
return(
<Stack.Navigator>
<Stack.Screen name="Home" component={Home}/>
<Stack.Screen name="PokeDetails" component={PokeDetails}/>
</Stack.Navigator>
)
}
export default Root;
// App.js
import 'react-native-gesture-handler';
import React from 'react';
import { View , StyleSheet } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createDrawerNavigator } from "#react-navigation/drawer";
import About from "./screens/About";
import Root from "./Route/Root";
import PokeDetails from "./screens/PokeDetails"
const App =()=> {
const Drawer = createDrawerNavigator();
return(
<View style={styles.container}>
<NavigationContainer>
<Drawer.Navigator>
<Drawer.Screen name="Home" component={Root}/>
<Drawer.Screen name="About" component={About}/>
</Drawer.Navigator>
</NavigationContainer>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1
}
})
export default App;
I don't know if i understood your question. You already pass an item props to your PokeDetails component from your Homescreen, but there is no item in the props your receive in it. just add it and i guess you will access to your data and will be able to display it:
const PokeDetails =({name, imageUrl, detail, item})=> {
return(
<View style={GlobalStyles.container}>
<Image source={{uri: imageUrl}} style={{height: 50, width: 50}}/>
<Text style={GlobalStyles.pokeText}>{name}</Text>
<Text>This text is explicitly written</Text>
// add your stuff here...
<Text>{item.something}</Text>
</View>
)
}
By the way, since you already have the item prop, you can remove the name which already comes from item :)

Stacknavigator not navigating to new screen while using functional component

Here's my App.js
import React, {Component} from 'react';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import {Provider} from 'react-redux';
import {createStore} from 'redux';
import Reducers from './app/reducers';
import Preload from './app/Screens/Preload';
import HomeScreen from './app/Screens/HomeScreen';
let store = createStore(
Reducers,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
const AppNavigator = createStackNavigator({
Home: {screen: HomeScreen, navigationOptions: {header: null }},
Preload: {screen: Preload, navigationOptions: {header: null }},
});
const AppContainer = createAppContainer(AppNavigator);
export default class App extends Component {
render () {
return (
<Provider store={store}>
<AppContainer/>
</Provider>
)
}
}
HomeScreen.js has a nested Wrap.js component which in turn has a Header.js component where the onPress event is handled to load a new screen, in this case the Preload.js screen.
When I press the TouchableOpacity component, there is no error thrown but nothing happens either. The new screen doesn't load. Please let me know how to load new screens while using functional components.
Here are the respective components mentioned above.
Wrap.js
import React from 'react'
import { View, Text, StyleSheet, StatusBar, Platform, SafeAreaView, ScrollView } from 'react-native'
import Colors from '../../Constants/Colors'
import Header from './Header'
const Wrap = (props) => {
return (
<SafeAreaView style={styles.mainWrapper}>
<ScrollView>
<Header />
{props.children}
</ScrollView>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
mainWrapper: {
backgroundColor: Colors.orange,
height: "100%",
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0
}
})
export default Wrap
Header.js
import React from 'react'
import { View, Text, StyleSheet, Image, TouchableOpacity } from 'react-native'
import { FontAwesome } from '#expo/vector-icons';
import SourceImages from '../../Constants/SourceImages'
import Colors from '../../Constants/Colors'
import { NavigationActions } from 'react-navigation';
const {navigate} = NavigationActions;
const Header = () => {
return (
<View style={styles.wrapper}>
<View style={styles.menuIconWrapper}>
<TouchableOpacity style={styles.iconWrapper}
onPress={()=>{navigate('Preload')}}
>
<FontAwesome name="navicon" style={styles.icon} />
</TouchableOpacity>
</View>
<View style={styles.logoWrapper}>
<Image style={styles.logo} source={ SourceImages.logo } resizeMode="contain" />
</View>
<View style={styles.cartIconWrapper}>
<TouchableOpacity style={styles.iconWrapper} >
<FontAwesome name="shopping-basket" style={styles.icon} />
</TouchableOpacity>
</View>
</View>
)
}
export default Header
You have to do it in following way:
1- import { withNavigation } from 'react-navigation' instead of NavigationActions
2- use const Header = (props) instead of const Header = ()
3- use props.navigation instead of const {navigate} = NavigationActions;
4- export default withNavigation(Header) instead of export default Header
It will work this way:
import { withNavigation } from 'react-navigation'
const Header = (props)
props.navigation.navigate('Preload')
export default withNavigation(Header)

Categories

Resources