Passing Data Between Screens
Most navigation involves passing data — tapping an item in a list should open a detail screen for that specific item. React Navigation handles this with route params: you pass an object when navigating, and the destination screen reads it from the route prop.
Sending Params
Pass a second argument to navigation.navigate with the data you want to send:
function HomeScreen({ navigation }) {
return (
<View style={styles.container}>
<Text style={styles.title}>Home Screen</Text>
<Button
title="View Item #42"
onPress={() => navigation.navigate('Details', { itemId: 42, title: 'Widget' })}
/>
</View>
);
}
The object { itemId: 42, title: 'Widget' } is now available on the Details screen.
Reading Params
The destination screen receives a route prop alongside navigation. Params live at route.params:
function DetailsScreen({ route, navigation }) {
const { itemId, title } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<Text>Item ID: {itemId}</Text>
<Button title="Go Back" onPress={() => navigation.goBack()} />
</View>
);
}
Setting Default Params
You can define default values with initialParams on the screen definition. These are used if the screen is navigated to without any params:
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 0, title: 'Unknown' }}
/>
Params passed via navigate merge with and override initialParams.
Updating Params
A screen can update its own params with navigation.setParams:
function DetailsScreen({ route, navigation }) {
const { itemId, title } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<Button
title="Rename to Gadget"
onPress={() => navigation.setParams({ title: 'Gadget' })}
/>
</View>
);
}
This is useful when a screen modifies data and wants to reflect the change in its own params (for example, updating a header title).
Passing Params Back
Sometimes the previous screen needs to know what happened. A common pattern is to pass a callback:
function HomeScreen({ navigation }) {
const [selectedColor, setSelectedColor] = React.useState('none');
return (
<View style={styles.container}>
<Text>Selected: {selectedColor}</Text>
<Button
title="Pick a Color"
onPress={() =>
navigation.navigate('ColorPicker', {
onSelect: (color) => setSelectedColor(color),
})
}
/>
</View>
);
}
function ColorPickerScreen({ route, navigation }) {
const { onSelect } = route.params;
const pick = (color) => {
onSelect(color);
navigation.goBack();
};
return (
<View style={styles.container}>
<Button title="Red" onPress={() => pick('red')} />
<Button title="Blue" onPress={() => pick('blue')} />
</View>
);
}
Complete Example
Here's a list-to-detail flow passing an item's data:
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { View, Text, Button, FlatList, TouchableOpacity, StyleSheet } from 'react-native';
const Stack = createNativeStackNavigator();
const ITEMS = [
{ id: 1, title: 'Learn React Native', description: 'Build mobile apps with React' },
{ id: 2, title: 'Learn Navigation', description: 'Navigate between screens' },
{ id: 3, title: 'Build an App', description: 'Put it all together' },
];
function HomeScreen({ navigation }) {
return (
<FlatList
data={ITEMS}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.item}
onPress={() => navigation.navigate('Details', { itemId: item.id, title: item.title, description: item.description })}
>
<Text style={styles.itemTitle}>{item.title}</Text>
</TouchableOpacity>
)}
/>
);
}
function DetailsScreen({ route }) {
const { title, description } = route.params;
return (
<View style={styles.container}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.description}>{description}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 16 },
title: { fontSize: 24, fontWeight: 'bold', marginBottom: 8 },
description: { fontSize: 16, color: '#666' },
item: { padding: 16, borderBottomWidth: 1, borderBottomColor: '#eee' },
itemTitle: { fontSize: 18 },
});
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'My Items' }} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
Tap any item in the list and the Details screen shows its title and description. The native stack handles the transition animation and back gesture automatically.
In the next lesson we'll customize the header — changing titles, colors, and adding buttons.