React Native Navigation
Master navigation patterns in React Native apps
Navigation is crucial for mobile apps. React Navigation is the most popular navigation library for React Native, providing stack, tab, and drawer navigation patterns with smooth animations and gesture support.
Getting Started with React Navigation
Installation
# Install core navigation library npm install @react-navigation/native # Install required dependencies npm install react-native-screens react-native-safe-area-context # For iOS, run pod install cd ios && pod install && cd .. # For Expo projects, install Expo-compatible versions npx expo install react-native-screens react-native-safe-area-context
Basic Setup
// App.js import React from 'react'; import { NavigationContainer } from '@react-navigation/native'; export default function App() { return ( <NavigationContainer> {/* Your navigators go here */} </NavigationContainer> ); }
Navigation Types
Stack Navigation
Navigate between screens in a stack-like manner
Use Case: Perfect for hierarchical navigation like Settings → Profile → Edit Profile
npm install @react-navigation/native @react-navigation/native-stack
Example Implementation:
import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; const Stack = createNativeStackNavigator(); function App() { return ( <NavigationContainer> <Stack.Navigator initialRouteName="Home"> <Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Welcome' }} /> <Stack.Screen name="Details" component={DetailsScreen} options={{ title: 'Details' }} /> </Stack.Navigator> </NavigationContainer> ); }
Tab Navigation
Bottom tab navigation for main app sections
Use Case: Main app navigation like Home, Search, Profile, Settings tabs
npm install @react-navigation/bottom-tabs
Example Implementation:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { Ionicons } from '@expo/vector-icons'; const Tab = createBottomTabNavigator(); function MyTabs() { return ( <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { let iconName; if (route.name === 'Home') { iconName = focused ? 'home' : 'home-outline'; } else if (route.name === 'Settings') { iconName = focused ? 'settings' : 'settings-outline'; } return <Ionicons name={iconName} size={size} color={color} />; }, tabBarActiveTintColor: 'tomato', tabBarInactiveTintColor: 'gray', })} > <Tab.Screen name="Home" component={HomeScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> ); }
Drawer Navigation
Side drawer navigation for additional options
Use Case: Secondary navigation, user menu, or app settings access
npm install @react-navigation/drawer react-native-gesture-handler react-native-reanimated
Example Implementation:
import { createDrawerNavigator } from '@react-navigation/drawer'; const Drawer = createDrawerNavigator(); function MyDrawer() { return ( <Drawer.Navigator screenOptions={{ drawerStyle: { backgroundColor: '#c6cbef', width: 240, }, drawerActiveTintColor: '#e91e63', drawerLabelStyle: { marginLeft: -25, fontFamily: 'Roboto-Medium', fontSize: 15, }, }} > <Drawer.Screen name="Home" component={HomeScreen} /> <Drawer.Screen name="Profile" component={ProfileScreen} /> <Drawer.Screen name="Settings" component={SettingsScreen} /> </Drawer.Navigator> ); }
Navigation Hooks
useNavigation
Access navigation object from any component
import { useNavigation } from '@react-navigation/native'; function MyComponent() { const navigation = useNavigation(); return ( <TouchableOpacity onPress={() => navigation.navigate('Details', { itemId: 86 })} > <Text>Go to Details</Text> </TouchableOpacity> ); }
useRoute
Access route object and parameters
import { useRoute } from '@react-navigation/native'; function DetailsScreen() { const route = useRoute(); const { itemId, otherParam } = route.params; return ( <View> <Text>Details Screen</Text> <Text>Item ID: {itemId}</Text> <Text>Other Param: {otherParam}</Text> </View> ); }
useFocusEffect
Run side effects when screen comes into focus
import { useFocusEffect } from '@react-navigation/native'; import { useCallback } from 'react'; function ProfileScreen() { useFocusEffect( useCallback(() => { // Do something when the screen is focused console.log('Screen is focused'); return () => { // Do something when the screen is unfocused console.log('Screen is unfocused'); }; }, []) ); return <View>{/* Screen content */}</View>; }
Complete Navigation Example
App with Stack + Tab Navigation
import React from 'react'; import { View, Text, TouchableOpacity, StyleSheet } from 'react-native'; import { NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { Ionicons } from '@expo/vector-icons'; const Stack = createNativeStackNavigator(); const Tab = createBottomTabNavigator(); // Screen Components function HomeScreen({ navigation }) { return ( <View style={styles.container}> <Text style={styles.title}>Home Screen</Text> <TouchableOpacity style={styles.button} onPress={() => navigation.navigate('Details', { itemId: 86, otherParam: 'anything you want here' })} > <Text style={styles.buttonText}>Go to Details</Text> </TouchableOpacity> </View> ); } function DetailsScreen({ route, navigation }) { const { itemId, otherParam } = route.params; return ( <View style={styles.container}> <Text style={styles.title}>Details Screen</Text> <Text>Item ID: {JSON.stringify(itemId)}</Text> <Text>Other Param: {JSON.stringify(otherParam)}</Text> <TouchableOpacity style={styles.button} onPress={() => navigation.goBack()} > <Text style={styles.buttonText}>Go Back</Text> </TouchableOpacity> </View> ); } function ProfileScreen() { return ( <View style={styles.container}> <Text style={styles.title}>Profile Screen</Text> </View> ); } function SettingsScreen() { return ( <View style={styles.container}> <Text style={styles.title}>Settings Screen</Text> </View> ); } // Stack Navigator for Home flow function HomeStack() { return ( <Stack.Navigator> <Stack.Screen name="HomeMain" component={HomeScreen} options={{ title: 'Home' }} /> <Stack.Screen name="Details" component={DetailsScreen} options={{ title: 'Details' }} /> </Stack.Navigator> ); } // Tab Navigator function TabNavigator() { return ( <Tab.Navigator screenOptions={({ route }) => ({ tabBarIcon: ({ focused, color, size }) => { let iconName; if (route.name === 'Home') { iconName = focused ? 'home' : 'home-outline'; } else if (route.name === 'Profile') { iconName = focused ? 'person' : 'person-outline'; } else if (route.name === 'Settings') { iconName = focused ? 'settings' : 'settings-outline'; } return <Ionicons name={iconName} size={size} color={color} />; }, tabBarActiveTintColor: '#007AFF', tabBarInactiveTintColor: 'gray', headerShown: false, })} > <Tab.Screen name="Home" component={HomeStack} /> <Tab.Screen name="Profile" component={ProfileScreen} /> <Tab.Screen name="Settings" component={SettingsScreen} /> </Tab.Navigator> ); } // Main App Component export default function App() { return ( <NavigationContainer> <TabNavigator /> </NavigationContainer> ); } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 20, }, title: { fontSize: 24, fontWeight: 'bold', marginBottom: 20, }, button: { backgroundColor: '#007AFF', paddingHorizontal: 20, paddingVertical: 10, borderRadius: 8, marginTop: 10, }, buttonText: { color: 'white', fontSize: 16, fontWeight: 'bold', }, });
Advanced Navigation Patterns
Deep Linking
Handle URLs that open specific screens in your app
const linking = { prefixes: ['myapp://'], config: { screens: { Home: 'home', Profile: 'profile/:userId', }, }, }; <NavigationContainer linking={linking}> {/* navigators */} </NavigationContainer>
Authentication Flow
Conditional navigation based on authentication state
function App() { const [isLoggedIn, setIsLoggedIn] = useState(false); return ( <NavigationContainer> {isLoggedIn ? ( <MainTabNavigator /> ) : ( <AuthStackNavigator /> )} </NavigationContainer> ); }
Modal Screens
Present screens as modals with custom animations
<Stack.Navigator> <Stack.Group> <Stack.Screen name="Home" component={Home} /> </Stack.Group> <Stack.Group screenOptions={{ presentation: 'modal' }}> <Stack.Screen name="MyModal" component={Modal} /> </Stack.Group> </Stack.Navigator>
Custom Transitions
Create custom screen transition animations
<Stack.Screen name="Profile" component={Profile} options={{ transitionSpec: { open: { animation: 'timing', config: { duration: 500 } }, close: { animation: 'timing', config: { duration: 500 } }, }, }} />
Navigation Best Practices
✅ Best Practices
- • Use TypeScript for type-safe navigation
- • Implement proper deep linking
- • Handle navigation state persistence
- • Use appropriate navigation patterns for your app
- • Test navigation flows thoroughly
- • Implement proper loading and error states
❌ Common Mistakes
- • Don't nest navigators unnecessarily
- • Avoid complex navigation hierarchies
- • Don't ignore platform-specific navigation patterns
- • Avoid passing large objects as route params
- • Don't forget to handle back button on Android
- • Avoid blocking navigation with heavy operations