I am using react native drawer with navigation 5, I have created a drawer but from the drawer when I click some of option to navigate to next screen it gives me error like "Undefined is not object.. this.props" and when I define prop on top like const navigation = this.props.navigation it then gives me error "Navigation is undefined..."
This is my Drawer where my content is placed:
export function DrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<View
style={
styles.drawerContent
}
>
<View style={styles.userInfoSection}>
<Avatar.Image
...
/>
</View>
<Drawer.Section style={styles.drawerSection}>
<DrawerItem
label="Preferences"
onPress={() => {}}
/>
<DrawerItem
label="Classes"
onPress={() => this.props.navigation.navigate('ClassHome')} //Over Here I want to navigation
/>
</Drawer.Section>
</View>
</DrawerContentScrollView>
);
}
And this is where I placed my Drawer Screens:
import * as React from 'react';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HomeTimeTable from './HomeTimeTable';
import {DrawerContent} from './DrawerContent';
import ClassHome from './ClassHome';
const Drawer = createDrawerNavigator();
export default class DrawerScreens extends React.Component {
render(){
return (
<Drawer.Navigator drawerContent={() => <DrawerContent navigation = {this.props.navigation} />}>
<Drawer.Screen name="HomeTimeTable" component={HomeTimeTable} />
<Drawer.Screen name="ClassHome" component={ClassHome} />
</Drawer.Navigator>
);
}
}
You have to pass props from drawerContent to your DrawerContent as below :
import * as React from 'react';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HomeTimeTable from './HomeTimeTable';
import {DrawerContent} from './DrawerContent';
import ClassHome from './ClassHome';
const Drawer = createDrawerNavigator();
export default class DrawerScreens extends React.Component {
render(){
return (
<Drawer.Navigator drawerContent={(props) => <DrawerContent {...props}/>}> {/* pass props here */}
<Drawer.Screen name="HomeTimeTable" component={HomeTimeTable} />
<Drawer.Screen name="ClassHome" component={ClassHome} />
</Drawer.Navigator>
);
}
}
Now, you can use that props directly in your custom component :
export function DrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<View
style={
styles.drawerContent
}
>
<View style={styles.userInfoSection}>
<Avatar.Image
...
/>
</View>
<Drawer.Section style={styles.drawerSection}>
<DrawerItem
label="Preferences"
onPress={() => {}}
/>
<DrawerItem
label="Classes"
onPress={() => props.navigation.navigate('ClassHome')} // user props here
/>
</Drawer.Section>
</View>
</DrawerContentScrollView>
);
}
According to the documentation, the navigation prop should be passed by default to the DrawerContent. I would recommend doing it this way:
import * as React from 'react';
import { createDrawerNavigator } from '#react-navigation/drawer';
import HomeTimeTable from './HomeTimeTable';
import {DrawerContent} from './DrawerContent';
import ClassHome from './ClassHome';
const Drawer = createDrawerNavigator();
export default class DrawerScreens extends React.Component {
render(){
return (
<Drawer.Navigator drawerContent={DrawerContent}>
<Drawer.Screen name="HomeTimeTable" component={HomeTimeTable} />
<Drawer.Screen name="ClassHome" component={ClassHome} />
</Drawer.Navigator>
);
}
}
Related
I have a login screen then from there I navigate to home screen, and on home screen there are 4 buttons Alphabets, Ch-1,Ch-2 and Ch-3, by pressing each of those buttons, I can easily navigate to correct screens but Inside Alphabet screen, I have 2 more buttons Learn and Give test But when I press those, nothing happens , i can't navigate to the respective screens plus there are no errors. I guess its nested navigation.
I might sound stupid to an expert out there :) but I am new (from scratch) to react native and navigation stuff i really have no idea what to do! Will be really thankful if someone helps!
CODE IS GIVEN BELOW:
This is my home.js (its in folder screens):
import React from "react";
import {View, StyleSheet, Text} from 'react-native';
import { TouchableOpacity } from "react-native-gesture-handler";
import { Auth } from "../services";
export default home =({navigation}) => {
return (
<View style={styles.body}>
<Text style={styles.toptext}>
Merheba!
</Text>
<TouchableOpacity onPress={() => navigation.navigate('alphabets')}
style={styles.button}
>
<Text style={styles.buttontext}>Alphabets</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('ch1')}
style={styles.button}
>
<Text style={styles.buttontext}>Chapter 1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('ch2')}
style={styles.button}
>
<Text style={styles.buttontext}>Chapter 2</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('ch3')}
style={styles.button}
>
<Text style={styles.buttontext}>Chapter 3</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => Auth.signOut()}
style={styles.button}
>
<Text style={styles.buttontext}>Sign Out</Text>
</TouchableOpacity>
</View>
)
}
This is index.js from screens folder:
export {default as home} from './home';
export {default as login} from './login';
export {default as forgotp} from './login';
export {default as signup} from './signup';
export {default as alphabets} from './alphabets';
export {default as alphl} from './alphl';
export {default as alpht} from './alpht';
export {default as ch1} from './ch1';
export {default as ch2} from './ch2';
export {default as ch3} from './ch3';
This is alphabets.js from screens folder:
import { NavigationContainer } from "#react-navigation/native";
import React from "react";
import {View, StyleSheet, Text} from 'react-native';
import { TouchableOpacity } from "react-native-gesture-handler";
export default alphabets =({navigation}) => {
return (
<View style={styles.body}>
<Text style={styles.toptext}>
Merheba!
</Text>
<TouchableOpacity onPress={() => navigation.navigate('alphl')}
style={styles.button}
>
<Text style={styles.buttontext}>Learning Sheet</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('alpht')}
style={styles.button}
>
<Text style={styles.buttontext}>Give Test</Text>
</TouchableOpacity>
</View>
)
}
AppNavigation.js from navigation folder:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import home from '../screens/home';
import alphabets from '../screens/alphabets';
import ch1 from '../screens/ch1';
import ch2 from '../screens/ch2';
import ch3 from '../screens/ch3';
const stack=createStackNavigator();
export default AppNavigator = () => {
return(
<stack.Navigator
screenOptions={{
headerShown: null
}}
>
<stack.Screen name="home" component={home} />
<stack.Screen name="alphabets" component={alphabets} />
<stack.Screen name="ch1" component={ch1}/>
<stack.Screen name="ch2" component={ch2} />
<stack.Screen name="ch3" component={ch3} />
</stack.Navigator>
)
}
AlphNavigator.js from navigation folder:
import React from 'react';
import { createStackNavigator } from '#react-navigation/stack';
import alphl from '../screens/alphl';
import alpht from '../screens/alpht';
const stack=createStackNavigator();
export default AlphNavigator = () => {
return(
<stack.Navigator
screenOptions={{
headerShown: null
}}
>
<stack.Screen name="alphl" component={alphl} />
<stack.Screen name="alpht" component={alpht} />
</stack.Navigator>
)
}
& lastly index.js from navigation folder:
import React, {useState, useEffect} from 'react';
import { NavigationContainer } from '#react-navigation/native';
import AppNavigator from './AppNavigator';
import AuthNavigator from './AuthNavigator';
import auth from '#react-native-firebase/auth';
export default AppContainer = () => {
// Set an initializing state whilst Firebase connects
const [initializing, setInitializing] = useState(true);
const [user, setUser] = useState();
// Handle user state changes
function onAuthStateChanged(user) {
setUser(user);
if (initializing) setInitializing(false);
}
useEffect(() => {
const subscriber = auth().onAuthStateChanged(onAuthStateChanged);
return subscriber; // unsubscribe on unmount
}, []);
if (initializing) return null;
return(
<NavigationContainer>
{user ? <AppNavigator/> : <AuthNavigator/>}
</NavigationContainer>
)
}
You aren't defining your "AlphNavigator" in your "AppNavigator".
You should do this inside your AppNavigator:
export default AppNavigator = () => {
return(
<stack.Navigator
screenOptions={{
headerShown: null
}}
>
<stack.Screen name="home" component={home} />
<stack.Screen name="alphabets" component={alphabets} />
<stack.Screen name="alph" component={ AlphNavigator } /> /*here add your AlpNavigator*/
<stack.Screen name="ch1" component={ch1}/>
<stack.Screen name="ch2" component={ch2} />
<stack.Screen name="ch3" component={ch3} />
</stack.Navigator>
)}
It's normal that you do not have any error in this case, because React Navigation does not mark you as an error if a screen does not exist.
The above could be solved if you were using TypeScript.
So now, in order to access to nested navigation screens you should use:
navigation.navigate('alph', { screen: 'alphl' })
The first parameter is the name of the stack navigation, and the second one is an object with the name of the screen inside to this nested navigation.
I am trying to call openDrawer option from header of DrawerNavigation but the navigation prop does not contain openDrawer function.
import React from 'react';
import {View, TouchableOpacity} from 'react-native';
import {createDrawerNavigator} from '#react-navigation/drawer';
import Icon from 'react-native-vector-icons/Ionicons';
import {dimensions} from '../../constants/utils';
import CustomDrawerContent from './components/CustomDrawerContent';
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
screenOptionsProps = {
screenOptions: {
headerLeft: props => (
<View>
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<Icon
name="reorder-three-sharp"
size={dimensions.width * 0.08}
{...props}
/>
</TouchableOpacity>
</View>
),
},
};
return (
<Drawer.Navigator
{...screenOptionsProps}
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Dashboard" component={Dashboard} />
</Drawer.Navigator>
);
};
export default DrawerNavigator;
Whenever the Icon is being tapped drawer should be opened but navigation prop is not receiving anything and while consoling the navigation prop getting undefined as value. The props passed in drawerContent has openDrawer() method with in it but how to use it for screenOptions.
You can try "props.navigation.openDrawer()" or "props.navigation.toggleDrawer()"
headerLeft: props => (
<View>
<TouchableOpacity onPress={() =>
props.navigation.openDrawer()}>
<Icon
name="reorder-three-sharp"
size={dimensions.width * 0.08}
{...props}
/>
</TouchableOpacity>
</View>
),
Working on single time but when I return after to home screen it does not receive openDrawer() and closeDrawer() in props.navigation
For opening drawer navigation, finally i found the solution in the navigation props reference https://reactnavigation.org/docs/navigation-prop/. For anybody who got stuck with similar problem, it might be helpful.
So for the above problem i used useNavigation hook from #react-navigation/native which provides navigation object which can be further used for calling the openDrawer() method.
import React from 'react';
import {View, TouchableOpacity} from 'react-native';
import {createDrawerNavigator} from '#react-navigation/drawer';
import Icon from 'react-native-vector-icons/Ionicons';
import {dimensions} from '../../constants/utils';
import { DrawerActions, useNavigation } from "#react-navigation/native";
import CustomDrawerContent from './components/CustomDrawerContent';
const Drawer = createDrawerNavigator();
const DrawerNavigator = () => {
const navigation = useNavigation();
screenOptionsProps = {
screenOptions: {
headerLeft: props => (
<View>
<TouchableOpacity onPress={() => navigation.dispatch(DrawerActions.openDrawer())}>
<Icon
name="reorder-three-sharp"
size={dimensions.width * 0.08}
{...props}
/>
</TouchableOpacity>
</View>
),
},
};
return (
<Drawer.Navigator
{...screenOptionsProps}
drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name="Dashboard" component={Dashboard} />
</Drawer.Navigator>
);
};
export default DrawerNavigator;
This error occurs while using navigation. I don't understand why you do that.
The above error occurs when trying to navigate from HomeScreen to SignUp Detail through navigation.
I've looked everywhere, but I'm asking because I can't find the answer.
This error occurs while using navigation. I don't understand why you do that.
The above error occurs when trying to navigate from HomeScreen to SignUp Detail through navigation.
I've looked everywhere, but I'm asking because I can't find the answer.
this code App.js
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import SignUp from "./components/signupdetail/signup";
import HomeScreen from "./components/homeScreen";
const Stack = createStackNavigator();
const App = () => {
return (
<>
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="SignUp" component={SignUp} /> //my problem
</Stack.Navigator>
</NavigationContainer>
</>
);
};
export default App;
this code Homescreen
import Login from "./loginScreen/login";
import ButtonComponent from "./loginScreen/button";
import LostPassword from "./loginScreen/lostpassword";
import SocialLogin from "./loginScreen/sociallogin";
import SignUp from "./loginScreen/signup";
const HomeScreen = (props) => {
return (
<>
<SafeAreaView style={styles.container}>
<Text style={styles.header}>everywear</Text>
</SafeAreaView>
<View>
<Login />
<ButtonComponent />
<LostPassword />
<SocialLogin />
<SignUp navigation={props} />
</View>
</>
);
};
export default HomeScreen;
this code signup
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
const SignUp = (props) => {
const { navigation } = props;
return (
<>
<View style={styles.container}>
<Text style={styles.text}>혹시 처음이신가요?</Text>
<TouchableHighlight
onPress={() => {
navigation.navigate("SignUp");
}}
underlayColor="gray"
style={styles.button}
>
<>
<Text style={styles.signuptext}>회원가입</Text>
</>
</TouchableHighlight>
</View>
</>
);
};
export default SignUp;
There are different ways to fix this issue.
Easiest one would be to change like below
<SignUp navigation={props.navigation} />
This will pass the navigation prop correctly and the rest of the code would work as expected.
the useNavigation hook
you can use the hook like below
const SignUp = (props) => {
const navigation = useNavigation();
then no need to pass the prop from the parent.
I have the following code
Sidebar.js
import React from 'react'
import {View,Text,StyleSheet,Image,TouchableHighlight} from 'react-native';
import {Dimensions} from 'react-native';
import Feather from 'react-native-vector-icons/Feather';
// const WIDTH = Dimensions.get('window').width;
const HEIGHT = Dimensions.get('window').height;
const logo = require('../assets/logo1.png');
export default class Sidebar extends React.Component {
constructor(props){
super(props);
this.handleNavigation = this.handleNavigation.bind(this);// you should bind this to the method that call the props
}
handleNavigation(){
this.props.navigation.navigate('QuoteDay');
}
render() {
return (
<View style={styles.navigationContainer}>
<View style={styles.logoContainer}>
<Image style={styles.logo}
source={logo} />
</View>
</TouchableHighlight>
<TouchableHighlight
activeOpacity={0.6}
underlayColor="#ffffff"
onPress={() => alert('Pressed!')}>
<Text style={styles.listitem}> <Feather name="edit" size={30} color="#273746"/> Quotes </Text>
</TouchableHighlight>
<TouchableHighlight
activeOpacity={0.6}
underlayColor="#ffffff"
onPress={this.handleNavigation}>
<Text style={styles.listitem}> <Feather name="sunrise" size={30} color="#273746"/> Quote of the Day </Text>
</TouchableHighlight>
</View>
</View>
)
}
}
App.js
import React from 'react';
import {DrawerLayoutAndroid} from 'react-native';
import {AppNavigator} from './screens/Navigation';
import Sidebar from './screens/Sidebar';
export default class App extends React.Component {
render(){
const navigationView = (
<Sidebar/>
);
return (
<DrawerLayoutAndroid
drawerWidth={300}
drawerPosition="left"
statusBarBackgroundColor="#F0B27A"
renderNavigationView={() => navigationView}
>
<AppNavigator />
</DrawerLayoutAndroid>
)
}
}
Navigation.js
import React from 'react';
import 'react-native-gesture-handler';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { HomeScreen } from './Home';
import { ModalScreen } from './Modal';
import { QuoteScreen } from './QuoteDay';
const { Navigator, Screen } = createStackNavigator();
const HomeNavigator = () => (
<Navigator mode="modal" headerMode='none'>
<Screen name='Home' component={HomeScreen} />
<Screen name='MyModal' component={ModalScreen}/>
<Screen name='QuoteDay' component={QuoteScreen}/>
</Navigator>
);
export const AppNavigator = () => (
<NavigationContainer>
<HomeNavigator/>
</NavigationContainer>
);
But it is giving me the following error
TypeError: undefined is not an object (evaluating 'this.props.navigation.navigate')
whenever I try to navigate from Sidebar.js to any other screen.
How should could I go about solving this sort of this problem.
The problem is that Sidebar is not rendered inside a screen in a navigator and does therefore not receive the navigation prop which explains the error you're getting.
I recommend you to use react navigation's Drawer (https://reactnavigation.org/docs/drawer-navigator/) instead of DrawerLayoutAndroid. You can still use your custom Sidebar component layout this way by passing Sidebar to the drawerContent prop of react navigation's Drawer navigator.
Navigation.js
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createDrawerNavigator} from '#react-navigation/drawer';
import Sidebar from './path';
// Other imports...
const Home = createStackNavigator();
const Main = createDrawerNavigator();
const MainNavigator = () => {
return (
<Main.Navigator
drawerStyle={{width: 240}}
drawerContent={(props) => <Sidebar {...props} />}>
<Main.Screen name="HomeNavigator" component={HomeNavigator} />
</Main.Navigator>
);
};
const HomeNavigator = () => (
<Home.Navigator mode="modal" headerMode="none">
<Home.Screen name="Home" component={HomeScreen} />
<Home.Screen name="MyModal" component={ModalScreen} />
<Home.Screen name="QuoteDay" component={QuoteScreen} />
</Home.Navigator>
);
export const AppNavigator = () => (
<NavigationContainer>
<MainNavigator />
</NavigationContainer>
);
App.js
// Be sure to import StatusBar from 'react-native' for setting the status bar color
export default class App extends React.Component {
componentDidMount() {
StatusBar.setBackgroundColor('#F0B27A');
}
render() {
return <AppNavigator />;
}
}
So the approach I've taken here is to create a Drawer Navigator and to make this the main navigator. The HomeNavigator is a screen of this MainNavigator. This way every screen inside MainNavigator has access to the drawer and the navigation prop; In this case that means HomeNavigator and every screen it has.
This is my App.js
import React from "react";
import Menu from "./components/Menu";
import HomeScreen from "./views/HomeScreen";
import SecondScreen from "./views/SecondScreen";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
const Stack = createStackNavigator();
export default function App() {
return (
<Container>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
/>
<Stack.Screen name="Second" component={SecondSCreen} />
</Stack.Navigator>
</NavigationContainer>
<Menu></Menu>
</Container>
);
}
It works, because it shows the HomeScreen on default, but I want to navigate to the second screen via the Menu-component:
import React from "react";
import { View, Text, TouchableOpacity } from "react-native";
class Menu extends React.Component {
render() {
return (
<View>
<TouchableOpacity
onPress={() => {
alert("Hi");
}}
>
<Text>HomeScreen</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
navigation.navigate("Second");
}}
>
<Text>Screen 2</Text>
</TouchableOpacity>
</View>
);
}
}
export default Menu;
The component is visible, but when I click on the second button I expect the SecondScreen to be openend.
But I get this error:
Can't find variable: navigation
What am I missing?
You should use the navigationRef for this scenario, as your menu is outside the navigation container
import { NavigationContainer } from '#react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<Container>
<NavigationContainer ref={navigationRef}>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
/>
<Stack.Screen name="Second" component={SecondSCreen} />
</Stack.Navigator>
</NavigationContainer>
<Menu></Menu>
</Container>
);
}
// RootNavigation.js
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
In menu js,
import {navigate} from 'RootNavigation';
class Menu extends React.Component {
render() {
return (
<View>
<TouchableOpacity
onPress={() => {
alert("Hi");
}}
>
<Text>HomeScreen</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
navigate("Second");
}}
>
<Text>Screen 2</Text>
</TouchableOpacity>
</View>
);
}
}