Build smooth navigation between multiple screens using React Navigation's stack and tab navigators.
Creative apps need intuitive navigation patterns. Users expect to:
Your Creative Studio's 7-screen architecture requires both tab navigation (main sections) and stack navigation (feature flows).
Install the required packages:
npm install @react-navigation/native @react-navigation/stack @react-navigation/bottom-tabs
expo install react-native-screens react-native-safe-area-context
Create the main navigation structure:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
// Placeholder screens
import HomeScreen from './screens/HomeScreen';
import CommunityScreen from './screens/CommunityScreen';
import ProfileScreen from './screens/ProfileScreen';
const Tab = createBottomTabNavigator();
function MainTabs() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Home') {
iconName = focused ? 'home' : 'home-outline';
} else if (route.name === 'Community') {
iconName = focused ? 'people' : 'people-outline';
} else if (route.name === 'Profile') {
iconName = focused ? 'person' : 'person-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: '#6366f1',
tabBarInactiveTintColor: '#9ca3af',
tabBarStyle: {
backgroundColor: '#000',
borderTopColor: '#374151',
},
headerShown: false,
})}
>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Community" component={CommunityScreen} />
<Tab.Screen name="Profile" component={ProfileScreen} />
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MainTabs />
</NavigationContainer>
);
}
For your Creative Studio's complete navigation:
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
// Import all your screens
import HomeScreen from './screens/HomeScreen';
import CameraScreen from './screens/CameraScreen';
import EditorScreen from './screens/EditorScreen';
import GalleryScreen from './screens/GalleryScreen';
import AlbumsScreen from './screens/AlbumsScreen';
import ProfileScreen from './screens/ProfileScreen';
import CommunityScreen from './screens/CommunityScreen';
const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
// Main tab navigation
function MainTabs() {
return (
<Tab.Navigator
screenOptions={{
tabBarActiveTintColor: '#6366f1',
tabBarInactiveTintColor: '#9ca3af',
tabBarStyle: { backgroundColor: '#000' },
headerShown: false,
}}
>
<Tab.Screen
name="Home"
component={HomeScreen}
options={{
tabBarIcon: ({ color, size }) => (
<Ionicons name="home-outline" size={size} color={color} />
),
}}
/>
<Tab.Screen
name="Community"
component={CommunityScreen}
options={{
tabBarIcon: ({ color, size }) => (
<Ionicons name="people-outline" size={size} color={color} />
),
}}
/>
<Tab.Screen
name="Profile"
component={ProfileScreen}
options={{
tabBarIcon: ({ color, size }) => (
<Ionicons name="person-outline" size={size} color={color} />
),
}}
/>
</Tab.Navigator>
);
}
// Root stack navigator
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
{/* Tab navigation as main screen */}
<Stack.Screen name="MainTabs" component={MainTabs} />
{/* Modal/overlay screens */}
<Stack.Screen name="Camera" component={CameraScreen} />
<Stack.Screen name="Editor" component={EditorScreen} />
<Stack.Screen name="Gallery" component={GalleryScreen} />
<Stack.Screen name="Albums" component={AlbumsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
function HomeScreen({ navigation }) {
const openCamera = () => {
navigation.navigate('Camera');
};
const openGallery = () => {
navigation.navigate('Gallery');
};
return (
<View style={styles.container}>
<Text style={styles.title}>Creative Studio</Text>
<TouchableOpacity style={styles.button} onPress={openCamera}>
<Text style={styles.buttonText}>Take Photo</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={openGallery}>
<Text style={styles.buttonText}>Browse Gallery</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#000',
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 32,
fontWeight: 'bold',
color: 'white',
marginBottom: 40,
},
button: {
backgroundColor: '#6366f1',
paddingHorizontal: 32,
paddingVertical: 16,
borderRadius: 8,
marginVertical: 8,
width: '80%',
alignItems: 'center',
},
buttonText: {
color: 'white',
fontSize: 18,
fontWeight: 'bold',
},
});
// From Gallery Screen
const openEditor = (selectedPhoto) => {
navigation.navigate('Editor', {
photo: selectedPhoto,
mode: 'edit'
});
};
// In Editor Screen
function EditorScreen({ route, navigation }) {
const { photo, mode } = route.params;
const saveAndReturn = (editedPhoto) => {
// Navigate back and pass result
navigation.navigate('Gallery', {
updatedPhoto: editedPhoto
});
};
return (
// Editor UI here
);
}
import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';
function GalleryScreen({ route, navigation }) {
const [photos, setPhotos] = useState([]);
// Listen for screen focus (when returning)
useFocusEffect(
useCallback(() => {
if (route.params?.updatedPhoto) {
// Handle the returned photo
const { updatedPhoto } = route.params;
updatePhotoInGallery(updatedPhoto);
// Clear the param to avoid re-processing
navigation.setParams({ updatedPhoto: undefined });
}
}, [route.params?.updatedPhoto])
);
return (
// Gallery UI here
);
}
import { Alert } from 'react-native';
function EditorScreen({ navigation }) {
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const handleBackPress = () => {
if (hasUnsavedChanges) {
Alert.alert(
'Unsaved Changes',
'You have unsaved changes. Are you sure you want to leave?',
[
{ text: 'Stay', style: 'cancel' },
{
text: 'Leave',
style: 'destructive',
onPress: () => navigation.goBack()
}
]
);
} else {
navigation.goBack();
}
};
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity onPress={handleBackPress}>
<Ionicons name="arrow-back" size={24} color="white" />
</TouchableOpacity>
<Text style={styles.title}>Edit Photo</Text>
<TouchableOpacity onPress={savePhoto}>
<Text style={styles.saveText}>Save</Text>
</TouchableOpacity>
</View>
{/* Editor content */}
</View>
);
}
Your complete navigation enables these user flows:
You've mastered:
Next: You'll learn local data storage to persist user photos and preferences.