React Native course ยท Module 3: Navigation
Stack Navigation - Underwater Corridors
In this lesson8
Welcome to the corridors of Atlantis! Poseidon introduces you to the secrets of navigation - the system that allows you to move between screens of your application like through corridors of an underwater palace.
What is React Navigation?
React Navigation is the most popular navigation library for React Native. It allows you to create different types of navigation: stack, tab, drawer, and many more.
Installing React Navigation in Expo
# Install core
npx expo install @react-navigation/native
# Dependencies for Expo
npx expo install react-native-screens react-native-safe-area-context
# Stack Navigator
npx expo install @react-navigation/stack
npx expo install react-native-gesture-handler
# Or Native Stack (recommended, faster)
npx expo install @react-navigation/native-stackBasic Configuration
// App.tsx
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
// Define types for navigation parameters
type RootStackParamList = {
Home: undefined;
Details: { itemId: number; title: string };
Profile: { userId: string };
};
const Stack = createNativeStackNavigator<RootStackParamList>();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={HomeScreen}
options={{ title: 'Palace of Atlantis' }}
/>
<Stack.Screen
name="Details"
component={DetailsScreen}
options={{ title: 'Chamber of Details' }}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
/>
</Stack.Navigator>
</NavigationContainer>
);
}Home Screen with Navigation
import { NativeStackScreenProps } from '@react-navigation/native-stack';
type HomeScreenProps = NativeStackScreenProps<RootStackParamList, 'Home'>;
function HomeScreen({ navigation }: HomeScreenProps) {
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome to Atlantis!</Text>
{/* Navigation to a screen without parameters */}
<Pressable
style={styles.button}
onPress={() => navigation.navigate('Details', {
itemId: 42,
title: 'Poseidon\'s Chamber'
})}
>
<Text style={styles.buttonText}>Enter the chamber</Text>
</Pressable>
{/* Using push instead of navigate */}
<Pressable
style={styles.button}
onPress={() => navigation.push('Details', {
itemId: 43,
title: 'Triton\'s Chamber'
})}
>
<Text style={styles.buttonText}>Discover the next chamber</Text>
</Pressable>
</View>
);
}Difference Between navigate and push
// navigate - if you are already on this screen it does nothing; otherwise it pushes it onto the stack
// (since React Navigation 7 it no longer goes back to a screen lower in the stack, use popTo for that)
navigation.navigate('Details', { itemId: 1 });
// push - always adds a new screen to the stack (even if it's the same)
navigation.push('Details', { itemId: 2 });
// Example: image gallery where each image opens Details
// push allows having multiple Details screens on the stackReceiving Parameters
type DetailsScreenProps = NativeStackScreenProps<RootStackParamList, 'Details'>;
function DetailsScreen({ route, navigation }: DetailsScreenProps) {
// Parameters are typed thanks to RootStackParamList
const { itemId, title } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<Text>Chamber ID: {itemId}</Text>
{/* Go back to the previous screen */}
<Pressable onPress={() => navigation.goBack()}>
<Text>Go back</Text>
</Pressable>
{/* Go back to the first screen on the stack */}
<Pressable onPress={() => navigation.popToTop()}>
<Text>Return to the palace</Text>
</Pressable>
</View>
);
}Header Options
<Stack.Screen
name="Details"
component={DetailsScreen}
options={({ route }) => ({
title: route.params.title,
headerStyle: {
backgroundColor: '#1a5276',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
// Button in the header
headerRight: () => (
<Pressable onPress={() => alert('Info!')}>
<Text style={{ color: '#fff', marginRight: 10 }}>โน</Text>
</Pressable>
),
})}
/>Dynamic Options with navigation.setOptions
function DetailsScreen({ route, navigation }: DetailsScreenProps) {
const [count, setCount] = useState(0);
useEffect(() => {
// Dynamically change the title
navigation.setOptions({
title: `Chamber #${route.params.itemId}`,
headerRight: () => (
<Text style={{ color: '#fff' }}>Visits: {count}</Text>
),
});
}, [navigation, route.params.itemId, count]);
return (
<View>
<Pressable onPress={() => setCount(c => c + 1)}>
<Text>Increase counter</Text>
</Pressable>
</View>
);
}Stack Navigation is the foundation of navigation in React Native. It works like a stack of cards - each new screen is placed on top, and going back removes the top card.
Code for this lesson: App.tsx
import React from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function HomeScreen({ navigation }) {
return (
<View style={styles.screen}>
<Text style={styles.title}>Palace of Atlantis</Text>
{/* Navigate to the 'Details' screen and pass the itemId param */}
<Button
title="Enter the chamber"
onPress={() => navigation.navigate('Details', { itemId: 42 })}
/>
</View>
);
}
function DetailsScreen({ route }) {
const { itemId } = route.params;
return (
<View style={styles.screen}>
<Text style={styles.title}>Chamber #{itemId}</Text>
</View>
);
}
export default function App() {
return (
<NavigationContainer>
{/* TODO: add a <Stack.Navigator> with the prop initialRouteName="Home" */}
{/* TODO: inside it add <Stack.Screen name="Home" component={HomeScreen} /> */}
{/* TODO: add a second <Stack.Screen name="Details" component={DetailsScreen} /> */}
</NavigationContainer>
);
}
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1a5276',
gap: 16,
},
title: {
fontSize: 22,
color: '#fff',
fontWeight: '600',
},
});Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. What must wrap all navigation in React Navigation?
2. What is the difference between navigation.navigate() and navigation.push()?
These are 2 of 4 questions for this lesson. Solve the rest in the game.
Hands-on tasks in the game
- Vertical ordering
Arrange Stack Navigator elements from outermost to innermost:
- Click in order
Click the elements in the order of passing parameters to a screen:
- Code editor
Complete the Stack Navigator code.