this.props.navigation undefined is not an object - react-native

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.

Related

I can't change the screen

I've got a component(Bottom.js) inside of another component(LoginScreen.js), inside this component(Bottom.js) there is a button(TouchableOpacity), I want to press it and change the LoginScreen to RegisterScreen, but I can't! I tried to see the docs of react navigation and I still confused. Could someone help me?
App.js
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
//import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet } from 'react-native';
import LoginScreen from './src/screens/Login/LoginScreen';
import RegisterScreen from './src/screens/Register/RegisterScreen';
import mock from './src/mocks/Login'
const Stack = createStackNavigator();
const MyTheme = {
dark: false,
colors: {
background: 'rgb(7, 19, 24)',
},
};
export default function App(){
return (
<NavigationContainer theme={MyTheme}>
<Stack.Navigator screenOptions={{headerShown: false}}>
<Stack.Screen name='Login' >
{() => <LoginScreen {...mock}/>}
</Stack.Screen>
<Stack.Screen name='Register' >
{() => <RegisterScreen />}
</Stack.Screen>
</Stack.Navigator>
</NavigationContainer>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#071318',
},
});
LoginScreen.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import {Button, Input, Image} from 'react-native-elements'
import Top from './components/Top'
import Form from './components/Form'
import ButtonEnter from './components/ButtonEnter'
import Bottom from './components/Bottom'
export default function LoginScreen({top, form, buttonEnter, bottom, navigation})
{
return <>
<View style={styles.background}>
<StatusBar style='light'/>
<Top {...top}/>
<Form {...form}/>
<ButtonEnter {...buttonEnter}/>
<Bottom {...bottom} {...navigation}/>
</View>
</>
}
const styles = StyleSheet.create({
background:{
backgroundColor: "#071318"
},
text:{
color:'#AAA',
fontSize: 16,
},
logo:{
width: 160,
height: 160,
marginHorizontal: '25%',
marginTop: '15%'
}
})
Bottom.js
import React from 'react';
import { StyleSheet,View, Text, TouchableOpacity} from 'react-native';
export default function Bottom({signupButtonText, navigation})
{
return <>
<View style={styles.view}>
<TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Register')}>
<Text style={styles.helpButton}>{signupButtonText}</Text>
</TouchableOpacity>
</View>
</>
}
const styles = StyleSheet.create({
view:{
flexDirection:'row',
width: '70%',
height:'40%',
marginHorizontal:'15%',
justifyContent:'center',
},
button:{
marginTop: 16,
backgroundColor: '#0B2027',
paddingVertical: 12,
borderRadius:20,
width: 80,
alignItems: 'center',
position: 'absolute',
bottom: 30
},
image:{
width:'30%',
marginHorizontal:'35%'
},
helpButton:{
color:'white',
justifyContent:'space-around'
}
})
Register.js
import React from 'react'
import { View, Text } from 'react-native'
const RegisterScreen = ({navigation}) => {
return (
<View>
<Text>register</Text>
</View>
)
}
export default RegisterScreen
Bottom component is expecting to receive Navigation, not its properties, so try this:
<Bottom navigation={navigation} {...bottom}/>

Cannot read property 'navigation' of undefined Evaluating App.js Loading App.js

Looking to have button enter go into another screen:
need help with navigation screen.
I keep getting error:
Cannot read property 'navigation' of undefined
Evaluating App.js
Loading App.js
TypeError: Cannot read property 'navigation' of undefined
https://snack.expo.io/#ganiyat1/colorful-thrills
import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground, Image, Button } from 'react-native';
import Constants from 'expo-constants';
import { StackNavigator} from 'react-navigation';
import Books from './components/Books';
// You can import from local files
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
const Book = StackNavigator({
Books: { screen: Books },
});
const { navigate } = this.props.navigation;
export default function App() {
return (
<View style={styles.container}>
<View style={styles.topContainer}>
<Text style={styles.title}> Colorful Thrills
</Text >
</View>
<View style={styles.bottomContainer}></View>
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={require('./assets/bookcover.png')}
/>
<Text style={styles.paragraph}>
{"\n"} BOOKWORMS, UNITE! {"\n"} {"\n"}
Suspense, Mystery and Thrillers by Authors of Color
</Text>
<Button
color='#ff914d'
title= 'ENTER'
onPress={() =>
navigate('Books')}
/>
</View>
</View>
);
}
In the above code snippet, I don't see a default Navigator being returned form the entry file, which is App.js by default in React Native.
I assume that you just started to learn React Native, so I will spare you all the minor details and walk you through the solution.
I refactored the App.js file to a into a new component file in /components/Home.js.
Added a default stack Navigator in App.js which has two screens, Home and Books.
Now you can access all the Navigation props in your Home and Books component, as it is being declared in the Navigator variable in App.js
Here is a live demo of your code on Expo.
//App.js
import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground, Image, Button } from 'react-native';
import Constants from 'expo-constants';
import { StackNavigator} from 'react-navigation';
import Books from './components/Books';
import Home from './components/Home'
import { Card } from 'react-native-paper';
const Navigator = StackNavigator({
Books: { screen: Books },
Home:{screen:Home}
});
export default function App(props) {
return (
<Navigator />
);
}
//component/Books.js
import React, { useState } from 'react';
import { StyleSheet, SafeAreaView,Button } from 'react-native';
import MaterialTabs from 'react-native-material-tabs';
const Books = (props) => {
const {navigation} = props
const [selectedTab, setSelectedTab] = useState(0);
return (
<SafeAreaView style={styles.container}>
<MaterialTabs
items={['New Releases', 'All', 'BOM']}
selectedIndex={selectedTab}
onChange={setSelectedTab}
barColor="#1fbcd2"
indicatorColor="#ff914d"
activeTextColor="white"
/>
<Button
color='#ff914d'
title= 'Home'
onPress={() =>
navigation.navigate('Home')}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
export default Books
//component/Home.js
import React from 'react'
import {View,Text,StyleSheet,Button,Image} from 'react-native'
const Home = (props) => {
const {navigation} = props
return (
<View style={styles.container}>
<View style={styles.topContainer}>
<Text style={styles.title}> Colorful Thrills
</Text >
</View>
<View style={styles.bottomContainer}></View>
<View style={styles.imageContainer}>
<Image
style={styles.image}
source={require('../assets/bookcover.png')}
/>
<Text style={styles.paragraph}>
{"\n"} BOOKWORMS, UNITE! {"\n"} {"\n"}
Suspense, Mystery and Thrillers by Authors of Color
</Text>
<Button
color='#ff914d'
title= 'ENTER'
onPress={() =>
navigation.navigate('Books')}
/>
</View>
</View>
)
}
export default Home
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
topContainer: {
flex: 1,
backgroundColor: '#ff914d',
},
bottomContainer: {
flex: 1,
backgroundColor: '#96d0e3',
},
imageContainer: {
position: 'absolute',
width: '100%',
height: '100%',
justifyContent: 'center',
alignItems: 'center',
},
image: {
width: 300,
},
title:{
margin: 24,
marginTop: 50,
fontSize: 40,
fontWeight: 'bold',
textAlign: 'center',
fontFamily: 'GillSans-Italic',
},
paragraph: {
margin: 24,
marginTop: 0,
fontSize: 20,
fontWeight: 'bold',
textAlign: 'center',
}
});

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

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',
}
})

Add padding to a custom contentComponent for a DrawerNavigator to avoid overlaying the status bar

When using a basic DrawerNavigator, there is proper paddingTop that avoids overlaying content over the status bar; however, when adding a custom contentComponent, the padding is not there. Code: https://github.com/myplaceonline/testreactexpo/tree/drawermargin
Without custom contentComponent on Android:
With custom contentComponent on Android:
I can add some explicit margin, but what value should I choose? I'm already using SafeAreaView, but I believe that's only for iOS.
Here's the code. Comment the contentComponent: CustomDrawerContentComponent, line to see the working view.
import React from 'react';
import { SafeAreaView, ScrollView, Text, View } from 'react-native';
import { createAppContainer, createDrawerNavigator, createStackNavigator, DrawerItems } from 'react-navigation';
class TestScreen extends React.Component {
static navigationOptions = {
title: "Test",
};
render() {
return (
<View style={{flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>Test</Text>
</View>
);
}
}
const CustomDrawerContentComponent = props => (
<SafeAreaView style={{flex: 1}} forceInset={{ top: "always", horizontal: "never" }}>
<ScrollView>
<DrawerItems {...props} />
</ScrollView>
</SafeAreaView>
);
export default AppDrawer = createAppContainer(
createDrawerNavigator(
{
DrawerTest: {
screen: createStackNavigator(
{
Test: TestScreen
},
),
navigationOptions: {
drawerLabel: "Test",
}
},
},
{
contentComponent: CustomDrawerContentComponent,
}
)
);
<div data-snack-id="#git/github.com/myplaceonline/testreactexpo#drawermargin" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.08);border-radius:4px;height:505px;width:100%"></div>
<script async src="https://snack.expo.io/embed.js"></script>
Solved with:
import Constants from 'expo-constants';
<ScrollView style={{paddingTop: Constants.statusBarHeight}}>

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>
);
}
}