TypeError: undefined is not an object (evaluating props.navigation.navigate) - react-native

I have an icon on the right side of my Header. When pressed I want to be transferred to another page. However, it comes up with an error.
This is my 'icon' screen:
import React, { Component } from 'react';
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native';
const Login = props => {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity
onPress={() => {
props.navigation.navigate({routeName: 'Login'});}}>
<Image
source={{
uri:
'https://clipartart.com/images/login-icon-clipart-5.jpg',
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
}
export default Login;
This is my 'navigation' screen:
import {createStackNavigator} from 'react-navigation-stack';
import {createAppContainer} from 'react-navigation';
import React from 'react';
import Homepage from './screens/Homepage';
import Checkoutpage from './screens/Checkoutpage';
import Filterpage from './screens/Filterpage';
import Locationpage from './screens/Locationpage';
import Menupage from './screens/MenuPage';
import Welcomepage from './screens/Welcomepage';
import Loginpage from './screens/Loginpage';
import Finalpage from './screens/Finalpage';
import Login from './Components/Login';
const Navigation = createStackNavigator({
Home:Homepage,
Checkout: Checkoutpage,
Filter: Filterpage,
Location: Locationpage,
Menu: Menupage,
Welcome: Welcomepage,
Login: Loginpage,
Final: Finalpage
},
{
defaultNavigationOptions: {
headerRight:() => <Login/>
}
}
);
I'm very new to react-native. So if you found the problem, can you please explain thoroughly so I understand. Thank you!!

So it looks like you are expecting the navigation object to be part of the props passed to your <Login/> component. This object is only defined for screen components in react-navigate.
This means that you need to get access to the navigation functionality some other way. Luckily, this library provides you with the useNavigation() hook. So using that in your component would look something like:
// react-navigation v5+
import { useNavigation } from '#react-navigation/native';
const Login = () => {
const navigation = useNavigation();
return (
<View style={{ flexDirection: "row" }}>
<TouchableOpacity
onPress={() => {
navigation.navigate({ routeName: "Login" });
}}
>
<Image
source={{
uri: "https://clipartart.com/images/login-icon-clipart-5.jpg",
}}
style={{
width: 40,
height: 40,
borderRadius: 40 / 2,
marginLeft: 15,
}}
/>
</TouchableOpacity>
</View>
);
};

It seems to me you are using React Navigation v4.x , in order to use the useNavigation hook you need to upgrade to v5.x.
The navigation prop will be passed to all screens by default and you can use the useNavigation hook like #faelks suggested (if needed in other components).
UPGRADE TO v5 FIRST.
Here you have a little example for v5.x version:
import React from 'react'
import { Button, View, StyleSheet } from 'react-native'
import { NavigationContainer } from '#react-navigation/native'
import { createStackNavigator } from '#react-navigation/stack'
const Home = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go to login" onPress={() => navigation.navigate('Login')} />
</View>
)
const Login = ({ navigation }) => (
<View style={styles.component}>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
)
const Main = createStackNavigator()
const mainConfig = {
// configuration for this stack
initialRouteName: "Home",
}
export default props => (
<NavigationContainer>
<Main.Navigator {...mainConfig}>
<Main.Screen name="Home" component={Home} />
<Main.Screen name="Login" component={Login} />
{/* Other screens for this stack */}
</Main.Navigator>
</NavigationContainer>
)
const styles = StyleSheet.create({
component: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
}
})

Related

React Native, how to import navigation container?

My idea is to have nav.js contain the navigation container for my mobile application, along with all of the screens here (i.e. the homescreen). This file would theoretically let me include buttons in another file that would let me navigate to the screen in the nav.js file that I specified with the button.
I made a constant for this called NavBar and exported it, but when I tried to import into my photo.js file (an example file where I want to include a button that lets me navigate to my 'Tasks' screen), I got the error:
Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them.
I tried simply making my own button in photo.js instead of :
<Button title="Go to tasks" color="lightblue" onPress={() => navigation.navigate('Tasks')}/>, but that only gave me the error that the variable navigation could not be found.
nav.js
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import { StyleSheet, View, Button, ScrollView } from 'react-native';
import TaskApp from './taskapp';
import AddTank from './tank';
const NavBar = () => {
const Stack = createNativeStackNavigator();
{/* Homescreen */}
const HomeScreen = ( {navigation} ) => {
return (
<ScrollView style={homeStyle.container}>
<AddTank />
<Button title="Go to tasks" color="lightblue" onPress={() => navigation.navigate('Tasks')}/>
</ScrollView>
)
}
{/* Default config */}
const Config = ( {navigation } ) => {
return (
<View></View>
)
}
return (
<NavigationContainer>
<Stack.Navigator initialRouteName='Home'>
<Stack.Screen name="Home" component={HomeScreen}/>
<Stack.Screen name="Tasks" component={TaskApp}/>
<Stack.Screen name="Config" component={Config}/>
</Stack.Navigator>
</NavigationContainer>
)
}
const homeStyle = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
tasks: {
flex: 1,
height: 30,
width: 30,
backgroundColor: '#E8EAED',
},
});
export default NavBar;
photo.js
import React, {useState, useEffect} from 'react';
import { StyleSheet, Text, View, Button, Image, ImageBackground } from 'react-native';
import { NavigationContainer, StackActions } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import * as ImagePicker from 'expo-image-picker';
import NavBar from './nav';
const AddPhoto = () => {
const add = {uri: 'https://media.discordapp.net/attachments/639282516997701652/976293252082839582/plus.png?width=461&height=461'}
const Stack = createNativeStackNavigator();
const [hasGalleryPermission, setHasGalleryPermission] = useState(null);
const[ image, setImage ] = useState(null);
useEffect(() => {
(async () => {
const galleryStatus = await ImagePicker.requestCameraMediaLibraryPermissionAsync();
setHasGalleryPermission(galleryStatus.status === 'granted');
})();
}, []);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4,3],
quality:1,
});
console.log(result);
if (!result.cancelled){
setImage(result.uri);
}
};
if (hasGalleryPermission === false){
return <Text>No access to internal storage.</Text>
}
return (
<View style={styles.container}>
{image && <ImageBackground source={{uri: image}} style={styles.tankPhoto}/>}
<Button title="Add photo" color="lightgreen" onPress={() => pickImage()} />
<NavBar />
</View>
)
}
const styles = StyleSheet.create({
container: {
borderColor: '#C0C0C0',
borderWidth: 1,
backgroundColor: '#FFF',
borderRadius: 50,
width: 330,
flex: 1,
alignItems: 'center',
marginLeft: 'auto',
marginRight: 'auto',
margin: 30,
},
tankPhoto: {
flex: 1,
height: 150,
width: 200,
borderWidth: 1,
margin: 25,
},
})
export default AddPhoto;
What am I doing wrong, or is there a better way to do this? What I need:
let me include buttons in another file that would let me navigate to the screen in the nav.js file that I specified with the button.
React native navigation documentation: https://reactnavigation.org/docs/getting-started
Move these lines outside the NavBar component:
const Stack = createNativeStackNavigator();
{/* Homescreen */}
const HomeScreen = ( {navigation} ) => {
return (
<ScrollView style={homeStyle.container}>
<AddTank />
<Button title="Go to tasks" color="lightblue" onPress={() => navigation.navigate('Tasks')}/>
</ScrollView>
)
}
{/* Default config */}
const Config = ( {navigation } ) => {
return (
<View></View>
)
}
I ended up making this work. I defined
const navigation = useNavigation();
in my code (under AddPhoto constant) and imported:
import { useNavigation } from '#react-navigation/native'; in the same file (photo.js).

React Native — React-Navigation back button on wrong side of appbar?

Okay so I'm just jumping into React Native and I'm going through the docs with the react-navigation package. Whenever a screen is pushed onto the stack, the animation goes from right-left by default—Also I'm noticing the back button is on the right side of the appbar instead of the left be default. Is this by design or have I set something up incorrectly?
Also ignore the FC I'm using, I know it's not recommended but I'm just getting a feel for RN 😅
See image and code below:
import { StatusBar } from "expo-status-bar";
import { Button, StyleSheet, Text, View } from "react-native";
import { createNativeStackNavigator } from "#react-navigation/native-stack";
import { BaseNavigationContainer } from "#react-navigation/native";
import { FC } from "react";
import { StackScreenProps } from "./Types";
const Home: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Hello World </Text>
<Button
title="Switch Page"
onPress={() => {
navigation.navigate("About");
}}
/>
</View>
);
};
const About: FC<StackScreenProps> = ({ navigation }) => {
return (
<View style={styles.container}>
<Text>Learn the Process First</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
};
const Stack = createNativeStackNavigator();
export default function App() {
return (
<BaseNavigationContainer>
{/* #ts-ignore */}
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={Home} />
<Stack.Screen name="About" component={About} />
</Stack.Navigator>
</BaseNavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});

perform card navigation with react-native-tab-view stationary?

I am currently using react-navigation and react-native-tab-view. If I want to navigate to another screen, but keep the tab view at the same place, how would I do that?
Using the React Navigation and React Native Tab View tutorials, you can rewrite the default React Native App.js file to look like the React Native Tab View's TabViewExample component. Wrap the TabViewExample component in React Navigation's NavigationContainer component.
Then. wrap the TabViewExample's FirstRoute component in Stack.Navigator component, move the FirstRoute component's code to a new component, e.g. FirstRouteScreen, and add another component to the FirstRoute's component, e.g. DetailsScreen. These will be the two screens that you want to navigate between whilst keeping the tab view at the same place.
Add a button to the FirstRouteScreen component which will allow you to navigate to the DetailsScreen.
The following is what it should look like:
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import React from "react";
import { Button, Dimensions, StyleSheet, Text, View } from "react-native";
import "react-native-gesture-handler";
import { SceneMap, TabView } from "react-native-tab-view";
function FirstRouteScreen({navigation}) {
return (
<View style={[styles.scene, { backgroundColor: "#ff4081" }]}>
<Text>First Route</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate("Details")}
/>
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Details Screen</Text>
</View>
);
}
const FirstRoute = () => (
<Stack.Navigator initialRouteName="First Route">
<Stack.Screen
name="First Route"
component={FirstRouteScreen}
options={{ title: "Overview" }}
/>
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
const SecondRoute = () => (
<View style={[styles.scene, { backgroundColor: "#673ab7" }]}>
<Text>Second Route</Text>
</View>
);
const initialLayout = { width: Dimensions.get("window").width };
const Stack = createStackNavigator();
export default function App() {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{ key: "first", title: "First" },
{ key: "second", title: "Second" },
]);
const renderScene = SceneMap({
first: FirstRoute,
second: SecondRoute,
});
return (
<NavigationContainer>
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
/>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
scene: {
flex: 1,
},
});
References:
Github. satya164/react-native-tab-view: A cross-platform Tab View component for React Native. https://github.com/satya164/react-native-tab-view. (Accessed November 22, 2020)
React Navigation. Getting started | React Navigation. https://reactnavigation.org/docs/getting-started. (Accessed November 22, 2020)
React Navigation. Hello React Navigation | React Navigation. https://reactnavigation.org/docs/hello-react-navigation. (Accessed November 22, 2020)
Moving between screens | React Navigation. https://reactnavigation.org/docs/navigating. (Accessed November 22, 2020)

this.props.navigation undefined is not an object

I am new in react native. I am using React navigation. But navigation is not working, giving an error:-
"props.navigation undefined is
not an object"
I am giving my project structure and code.
Project Structure:-
Code in App.js:-
import { createStackNavigator, createDrawerNavigator } from 'react-navigation';
import HomeLayout from './src/components/Home/Layout';
import SideMenuLayout from './src/components/DrawerMenu/SideMenu';
import { DetailsScreen } from './DetailsScreen';
const myDrawer = createDrawerNavigator({
Home:{
screen: HomeLayout
},
Details:{
screen: DetailsScreen
},
},{
contentComponent: SideMenuLayout,
drawerWidth: 876/3
})
const native = createStackNavigator({
Home:{
screen: myDrawer,
},
},{
headerMode: 'none',
})
export default native;
SideMenu.js(Layout for drawer navigator). In this section All menus has been rendered.-
import React, {Component} from 'react';
import { View, StyleSheet} from 'react-native';
import DrawerHeader from './DrawerHeader';
import DrawerMenu from './DrawerMenu';
class SideMenuLayout extends Component {
state = {
menuNames:[{
id:'0',
name:'My Profile'
},{
id:'1',
name:'Place Order'
},{
id:'2',
name:'Order History'
},{
id:'3',
name:'Payment'
},{
id:'4',
name:'Recharge'
},{
id:'5',
name:'Help'
},{
id:'6',
name:'Logout'
}]
}
render () {
return (
<View style={styles.container} >
<DrawerHeader/>
<DrawerMenu menuItems={this.state} style={{ marginTop: 106/3}}/>
</View>
);
}
}
export default SideMenuLayout;
const styles = StyleSheet.create({
container:{
flex:1,
backgroundColor: "#ffffff",
}
});
Drawer Menu.js. In this section all menus are rendered and want to navigate from here.
import React, {Component} from 'react';
import {FlatList, Text, View, StyleSheet,TouchableOpacity} from 'react-native';
import Dash from 'react-native-dash';
import { FontAwesome } from '#expo/vector-icons';
import { StackNavigator } from 'react-navigation';
const DrawerMenu = (props)=>{
const { navigate } = props.navigation;
return (
<View style={styles.menuContainer}>
<FlatList
data={props.menuItems.menuNames}
renderItem={(info) => (
<View>
<View
style={{
width:690/3,
backgroundColor: '#ffffff',
height:141/3,
paddingTop:48/3,
flexDirection:'row',
marginBottom:7
}}>
<View style={{position:"relative",width:390/3,height:'100%',backgroundColor:'#ffffff',alignSelf: 'flex-start'}}>
<TouchableOpacity onPress={()=>navigate('Details')}>
<Text style={{color:'#615b5b',fontSize:18,fontFamily:'sans-serif'}}>
{info.item.name}
</Text>
</TouchableOpacity>
</View>
<View
style={{
alignItems:"center",
justifyContent:'center',
position:"relative",
width:300/3,
backgroundColor:'#ffffff',
paddingRight:10,
paddingBottom:5,
}}>
<FontAwesome
style={{ alignSelf: 'flex-end'}}
name="angle-right"
size={18}
color="#615b5b"
/>
</View>
</View>
<Dash dashColor = '#d6d6d6' style={{width:'100%', height:1,alignSelf: 'flex-start'}}/>
</View>
)}
keyExtractor={(info, index) => info.id}
/>
</View>
);
}
export default DrawerMenu;
const styles = StyleSheet.create({
menuContainer:{
width: 700/3,
height:1425/3,
alignSelf: 'flex-end',
backgroundColor: '#ffffff',
paddingTop: 61/3,
}
});
The SideMenuLayout has a navigation prop passed to it automatically by the Drawer. So you need to pass that further to your DrawerMenu
<DrawerMenu navigation={this.props.navigation} menuItems={this.state} style={{ marginTop: 106/3}}/>
...
export default SideMenuLayout;
SideMenuLayout.propTypes = {
navigation: PropTypes.object // Or use flow, or it does not really matter. It's just type validation.
}
And the you can use navigate in your DrawerMenu like you use it now.

React Native Drawer navigation

Hi there I am trying to implement a drawer navigation in React Native
referring to this example.
I have almost finished the coding but I am getting an error while adding the contentComponent attribute in drawer class (HomeScreenRouter). After removing it I am able to run it successfully and everything is working well but when I add the sidebar menu using contentComponent it throws an error. I need a custom design for my drawer.
Here is my code for the drawer:
import React, { Component } from "react";
import HomeScreen from "./HomeScreen.js";
import MainScreenNavigator from "../DealScreen/mychat.js";
import Profiled from "../profilescreen/Profile.js";
import SideBar from "../SideBar/SideBar.js";
import { DrawerNavigator } from "react-navigation";
const HomeScreenRouter = DrawerNavigator(
{
Home: { screen: HomeScreen },
Chat: { screen: MainScreenNavigator },
Profile: { screen: Profiled },
},
{
contentComponent: props => <SideBar {...props} />
});
export default HomeScreenRouter;
Sidemenu :
import React from "react";
import { AppRegistry, Image, StatusBar } from "react-native";
import { Container, Content, Text, List, ListItem } from "native-base";
export default class SideBar extends React.Component {
render() {
const routes = ["Home", "Chat", "Profile"];
return (
<Container>
<Content>
<Image
source={{
uri: "https://github.com/GeekyAnts/NativeBase-KitchenSink/raw/react-navigation/img/drawer-cover.png"
}}
style={{
height: 120,
alignSelf: "stretch",
justifyContent: "center",
alignItems: "center"
}}>
<Image
square
style={{ height: 80, width: 70 }}
source={{
uri: "https://github.com/GeekyAnts/NativeBase-KitchenSink/raw/react-navigation/img/logo.png"
}}
/>
</Image>
<List
dataArray={routes}
renderRow={data => {
return (
<ListItem
button
onPress={() => this.props.navigation.navigate("Profile")}>
<Text>{data}</Text>
</ListItem>
);
}}
/>
</Content>
</Container>
);
}
}