Topic 50 of 56 · Full Stack Advanced

Topic 9 : Navigation

Lesson TL;DRTopic 9: Navigation 📖 8 min read · 🎯 advanced · 🧭 Prerequisites: usinglibrariesinphp, hooks Why this matters Up until now, your app has been a single screen — whatever you build just sits there. Bu...
8 min read·advanced·react-native · navigation · react-navigation · mobile

Topic 9: Navigation

📖 8 min read · 🎯 advanced · 🧭 Prerequisites: using-libraries-in-php, hooks

Why this matters

Up until now, your app has been a single screen — whatever you build just sits there. But real apps let users move around: tap a button and go to a new screen, hit back and return, open a side menu. That movement is what React Navigation handles. In this lesson, we're covering the three layouts you'll see in almost every production app — stack navigation, bottom tabs, and the side drawer. By the end, your app will feel like a real app, not just a prototype.

What You'll Learn

  • Install and configure React Navigation and its peer dependencies, including react-native-gesture-handler
  • Build stack navigation with @react-navigation/stack so screens slide in with a back button
  • Implement bottom tab navigation with @react-navigation/bottom-tabs for tab-bar switching
  • Set up drawer navigation with @react-navigation/drawer for a swipeable side menu

The Analogy

Think of React Navigation as the road network of Vizag. Stack navigation is a one-way highway — you merge onto it, move forward through screens, and hit the back button to exit the last on-ramp. Bottom tab navigation is like a city roundabout with four exits, each leading to a distinct district you can jump between freely. Drawer navigation is the hidden side-street map that slides out from the edge of town when you need it — always there, never in the way. NavigationContainer is city hall: nothing moves until it's open for business.

Chapter 1: Setting Up React Navigation

Before any screen can talk to another, the library stack must be in place.

Step 1: Install React Navigation and dependencies

npm install @react-navigation/native
npm install @react-navigation/stack
npm install @react-navigation/bottom-tabs
npm install @react-navigation/drawer
npm install react-native-screens react-native-safe-area-context
  • @react-navigation/native — the core container and hooks
  • @react-navigation/stack — push/pop screen navigator
  • @react-navigation/bottom-tabs — tab bar navigator
  • @react-navigation/drawer — side-drawer navigator
  • react-native-screens — native screen primitives for performance
  • react-native-safe-area-context — insets for notches and home bars

Step 2: Install and configure React Native Gesture Handler

React Navigation relies on react-native-gesture-handler for swipe-back and drawer gestures.

npm install react-native-gesture-handler

For React Native versions below 0.60, manually link the library:

react-native link react-native-gesture-handler

Then update MainActivity.java so the root view is gesture-aware:

android/app/src/main/java/com/yourappname/MainActivity.java

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView;

public class MainActivity extends ReactActivity {

    @Override
    protected String getMainComponentName() {
        return "yourappname";
    }

    @Override
    protected ReactActivityDelegate createReactActivityDelegate() {
        return new ReactActivityDelegate(this, getMainComponentName()) {
            @Override
            protected ReactRootView createRootView() {
                return new RNGestureHandlerEnabledRootView(MainActivity.this);
            }
        };
    }
}

Wrapping the root view with RNGestureHandlerEnabledRootView ensures gesture events propagate correctly on Android.

Chapter 2: Setting Up Stack Navigation

Stack navigation mimics the browser's history stack — push a screen on, pop it off. A header with a back button appears automatically.

Step 1: Create the screen components

HomeScreen.js

import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';

const HomeScreen = ({ navigation }) => {
  return (
    <View style={styles.container}>
      <Text>Home Screen</Text>
      <Button
        title="Go to Details"
        onPress={() => navigation.navigate('Details')}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default HomeScreen;

DetailsScreen.js

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const DetailsScreen = () => {
  return (
    <View style={styles.container}>
      <Text>Details Screen</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default DetailsScreen;

navigation.navigate('Details') pushes DetailsScreen onto the stack. The back button in the header calls navigation.goBack() implicitly.

Step 2: Configure the Stack Navigator in App.js

App.js

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import HomeScreen from './HomeScreen';
import DetailsScreen from './DetailsScreen';

const Stack = createStackNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator initialRouteName="Home">
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="Details" component={DetailsScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

initialRouteName="Home" sets which screen mounts first. NavigationContainer manages the navigation tree state and must wrap everything.

flowchart LR
    NC[NavigationContainer] --> SN[Stack.Navigator]
    SN --> HS[HomeScreen\n\"Home\"]
    SN --> DS[DetailsScreen\n\"Details\"]
    HS -- navigate('Details') --> DS
    DS -- back button --> HS

Chapter 3: Implementing Bottom Tab Navigation

Bottom tab navigation gives users instant access to top-level sections — no back button required.

Step 1: Create additional screen components

SettingsScreen.js

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const SettingsScreen = () => {
  return (
    <View style={styles.container}>
      <Text>Settings Screen</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default SettingsScreen;

ProfileScreen.js

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';

const ProfileScreen = () => {
  return (
    <View style={styles.container}>
      <Text>Profile Screen</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

export default ProfileScreen;

Step 2: Configure the Bottom Tab Navigator

App.js

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeScreen from './HomeScreen';
import DetailsScreen from './DetailsScreen';
import SettingsScreen from './SettingsScreen';
import ProfileScreen from './ProfileScreen';

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeScreen} />
        <Tab.Screen name="Details" component={DetailsScreen} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
        <Tab.Screen name="Profile" component={ProfileScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

createBottomTabNavigator() renders a persistent tab bar at the bottom. Each Tab.Screen entry becomes one tab. Tapping a tab switches the active screen without pushing it onto a stack — state for each tab is preserved independently.

Chapter 4: Implementing Drawer Navigation

A drawer navigator slides a menu panel in from the side, giving access to all top-level routes without occupying permanent screen real estate.

Step 1: Configure the Drawer Navigator

App.js

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import HomeScreen from './HomeScreen';
import DetailsScreen from './DetailsScreen';
import SettingsScreen from './SettingsScreen';
import ProfileScreen from './ProfileScreen';

const Drawer = createDrawerNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator initialRouteName="Home">
        <Drawer.Screen name="Home" component={HomeScreen} />
        <Drawer.Screen name="Details" component={DetailsScreen} />
        <Drawer.Screen name="Settings" component={SettingsScreen} />
        <Drawer.Screen name="Profile" component={ProfileScreen} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

createDrawerNavigator() from @react-navigation/drawer produces a side panel that users can open by swiping from the left edge or tapping the hamburger icon that appears in the header. initialRouteName="Home" dictates the default landing screen when the app opens.

flowchart TD
    NC[NavigationContainer] --> DN[Drawer.Navigator\ninitialRoute: Home]
    DN --> H[Home]
    DN --> D[Details]
    DN --> S[Settings]
    DN --> P[Profile]
    style DN fill:#2d6a4f,color:#fff

Choosing the right navigator

NavigatorPackageBest for
Stack@react-navigation/stackLinear flows, detail views
Bottom Tabs@react-navigation/bottom-tabs3–5 top-level sections
Drawer@react-navigation/drawerMany routes, infrequent access

Navigators can be nested — for example, a bottom tab navigator where one tab contains its own stack navigator. This is the most common pattern in production apps.

🧪 Try It Yourself

Task: Build a mini app that combines a bottom tab navigator with a nested stack inside the "Home" tab.

  1. Set up the two-tab shell:
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import { View, Text, Button } from 'react-native';

const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();

const HomeScreen = ({ navigation }) => (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Home</Text>
    <Button title="Go to Details" onPress={() => navigation.navigate('Details')} />
  </View>
);

const DetailsScreen = () => (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Details</Text>
  </View>
);

const SettingsScreen = () => (
  <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
    <Text>Settings</Text>
  </View>
);

function HomeStack() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Details" component={DetailsScreen} />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={HomeStack} />
        <Tab.Screen name="Settings" component={SettingsScreen} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

Success criterion: You see two tabs at the bottom. Tapping "Home" shows a "Go to Details" button. Pressing it pushes the Details screen with a back arrow in the header. The Settings tab stays accessible throughout. No crashes, no missing back button.

🔍 Checkpoint Quiz

Q1. Why must NavigationContainer wrap the entire navigator tree?

A) It provides the gesture handler context
B) It manages navigation state and links deep-link URLs to the correct screen
C) It renders the tab bar UI
D) It is only needed for drawer navigation

Q2. Given this snippet, what happens when the button is pressed?

<Button
  title="Go to Details"
  onPress={() => navigation.navigate('Details')}
/>

A) The Details screen replaces the current screen permanently
B) The Details screen is pushed onto the stack; a back button appears in the header
C) The app crashes because navigate is not a valid method
D) The drawer opens to show the Details entry

Q3. Which of the following code fragments correctly configures a drawer navigator with HomeScreen as the initial route?

// Option A
<Drawer.Navigator initialRouteName="Home">
  <Drawer.Screen name="Home" component={HomeScreen} />
</Drawer.Navigator>

// Option B
<Drawer.Navigator defaultScreen="Home">
  <Drawer.Screen name="Home" component={HomeScreen} />
</Drawer.Navigator>

A) Option A
B) Option B
C) Both are equivalent
D) Neither; drawers do not support an initial route

Q4. You have five sections in your app: Feed, Explore, Notifications, Messages, and Profile. Which navigator is the most appropriate top-level choice, and why?

A1. B — NavigationContainer holds the navigation state tree and handles deep linking. Without it, navigators have nowhere to store their state and the app will throw an error on mount.

A2. B — navigation.navigate('Details') pushes DetailsScreen onto the stack. React Navigation automatically adds a back button to the header because there is now a previous screen in the history.

A3. A — The correct prop is initialRouteName, not defaultScreen. Option B would be silently ignored and the first declared screen would be shown.

A4. Bottom Tab Navigator (@react-navigation/bottom-tabs) — five peer sections that users switch between freely are the canonical use case for tabs. A stack would force linear flow; a drawer buries sections behind a gesture instead of surfacing them permanently.

🪞 Recap

  • Install @react-navigation/native, navigator packages, react-native-screens, react-native-safe-area-context, and react-native-gesture-handler before writing any navigation code.
  • Wrap every navigator tree in <NavigationContainer> — it owns the navigation state.
  • Stack navigation (createStackNavigator) handles linear screen flows and provides a built-in header with a back button.
  • Bottom tab navigation (createBottomTabNavigator) renders a persistent tab bar for switching between peer-level screens.
  • Drawer navigation (createDrawerNavigator) provides a swipeable side menu, best for routes that are accessed less frequently.
  • Navigators can be nested — a common pattern is a bottom tab navigator containing stacks inside each tab.

📚 Further Reading

Like this topic? It’s one of 56 in Full Stack Advanced.

Block your seat for ₹2,500 and join the next cohort.