Search code examples
react-nativereact-navigationnavigation-drawerreact-navigation-v5

Not Able to Navigate from DrawerLayoutAndroid to any other screen in react native (android)


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.


Solution

  • 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.