Passing parameters to routes
Now that we know how to create a stack navigator with some routes and navigate between those routes, let's look at how we can pass data to routes when we navigate to them.
There are two pieces to this:
- Pass params as the second argument to navigation methods:
navigation.navigate('RouteName', { /* params go here */ }) - Read params from
route.paramsinside the screen component.
We recommend that the params you pass are JSON-serializable. That way, you'll be able to use state persistence and your screen components will have the right contract for implementing deep linking.
- Static
- Dynamic
function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
>
Go to Details
</Button>
</View>
);
}
function DetailsScreen({ route }) {
const navigation = useNavigation();
/* 2. Get the param */
const { itemId, otherParam } = route.params;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
onPress={
() =>
navigation.push('Details', {
// Randomly generate an ID for demonstration purposes
itemId: Math.floor(Math.random() * 100),
})
}
>
Go to Details... again
</Button>
<Button onPress={() => navigation.navigate('Home')}>Go to Home</Button>
<Button onPress={() => navigation.goBack()}>Go back</Button>
</View>
);
}
function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
onPress={() => {
/* 1. Navigate to the Details route with params */
navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
}}
>
Go to Details
</Button>
</View>
);
}
function DetailsScreen({ route }) {
const navigation = useNavigation();
/* 2. Get the param */
const { itemId, otherParam } = route.params;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Text>itemId: {JSON.stringify(itemId)}</Text>
<Text>otherParam: {JSON.stringify(otherParam)}</Text>
<Button
onPress={
() =>
navigation.push('Details', {
// Randomly generate an ID for demonstration purposes
itemId: Math.floor(Math.random() * 100),
})
}
>
Go to Details... again
</Button>
<Button onPress={() => navigation.navigate('Home')}>Go to Home</Button>
<Button onPress={() => navigation.goBack()}>Go back</Button>
</View>
);
}
Initial params
Initial params can be specified in initialParams. These are used when navigating to the screen without params, and are shallow merged with any params that you pass:
- Static
- Dynamic
{
Details: {
screen: DetailsScreen,
initialParams: { itemId: 42 },
},
}
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ itemId: 42 }}
/>
Updating params
Screens can update their params using navigation.setParams:
- Static
- Dynamic
navigation.setParams({
itemId: Math.floor(Math.random() * 100),
})
navigation.setParams({
itemId: Math.floor(Math.random() * 100),
})
setParams merges new params with existing ones. To replace params entirely, use replaceParams.
Avoid using setParams or replaceParams to update screen options like title. Use setOptions instead.
Passing params to a previous screen
Params can be passed to a previous screen as well, for example, when you have a "Create post" button that opens a new screen and you want to pass the post data back.
Use popTo to go back to the previous screen and pass params to it:
- Static
- Dynamic
function HomeScreen({ route }) {
const navigation = useNavigation();
// Use an effect to monitor the update to params
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
alert('New post: ' + route.params?.post);
}
}, [route.params?.post]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('CreatePost')}>
Create post
</Button>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</View>
);
}
function CreatePostScreen({ route }) {
const navigation = useNavigation();
const [postText, setPostText] = React.useState('');
return (
<>
<TextInput
multiline
placeholder="What's on your mind?"
style={{ height: 200, padding: 10, backgroundColor: 'white' }}
value={postText}
onChangeText={setPostText}
/>
<Button
onPress={() => {
// Pass params back to home screen
navigation.popTo('Home', { post: postText });
}}
>
Done
</Button>
</>
);
}
function HomeScreen({ route }) {
const navigation = useNavigation();
// Use an effect to monitor the update to params
React.useEffect(() => {
if (route.params?.post) {
// Post updated, do something with `route.params.post`
// For example, send the post to the server
alert('New post: ' + route.params?.post);
}
}, [route.params?.post]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Button onPress={() => navigation.navigate('CreatePost')}>
Create post
</Button>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</View>
);
}
function CreatePostScreen({ route }) {
const navigation = useNavigation();
const [postText, setPostText] = React.useState('');
return (
<>
<TextInput
multiline
placeholder="What's on your mind?"
style={{ height: 200, padding: 10, backgroundColor: 'white' }}
value={postText}
onChangeText={setPostText}
/>
<Button
onPress={() => {
// Pass params back to home screen
navigation.popTo('Home', { post: postText });
}}
>
Done
</Button>
</>
);
}
After pressing "Done", the home screen's route.params will be updated with the post text.
Passing params to a nested screen
If you have nested navigators, pass params using the same pattern as navigating to a nested screen:
- Static
- Dynamic
navigation.navigate('More', {
screen: 'Settings',
params: { userId: 'jane' },
})
navigation.navigate('More', {
screen: 'Settings',
params: { userId: 'jane' },
})
See Nesting navigators for more details on nesting.
Reserved param names
Some param names are reserved by React Navigation for nested navigator APIs:
screenparamsinitialstate
Avoid using these param names in your code. Trying to read these params in parent screens is not recommended and will cause unexpected behavior.
What should be in params
Params should contain the minimal information required to show a screen:
- Data to identify what to display (e.g. user id, item id)
- Screen-specific state (e.g. sort order, filters, page numbers)
Think of params like URL query parameters - they should contain identifiers and state, not actual data objects. The actual data should come from a global store or cache.
For example, say you have a Profile screen. You might be tempted to pass the user object in params:
// Don't do this
navigation.navigate('Profile', {
user: {
id: 'jane',
firstName: 'Jane',
lastName: 'Done',
age: 25,
},
});
This is an anti-pattern because:
- Data is duplicated, leading to stale data bugs
- Each screen navigating here needs to know how to fetch the user
- URLs/deep links would contain the full object, causing issues
Instead, pass only the ID:
navigation.navigate('Profile', { userId: 'jane' });
Then fetch the user data using the ID from a global cache or API. Libraries like React Query can help with fetching and caching.
Good examples of params:
- IDs:
navigation.navigate('Profile', { userId: 'jane' }) - Sorting/filtering:
navigation.navigate('Feeds', { sortBy: 'latest' }) - Pagination:
navigation.navigate('Chat', { beforeTime: 1603897152675 }) - Input data:
navigation.navigate('ComposeTweet', { title: 'Hello world!' })
Summary
- Params can be passed to screens as the second argument to navigation methods like
navigateandpush - Params can be read from the
paramsproperty of therouteobject - Params can be updated with
navigation.setParamsornavigation.replaceParams - Initial params can be passed via the
initialParamsprop - Params should contain the minimal data needed to identify a screen (e.g. IDs instead of full objects)
- Some param names are reserved by React Navigation