Skip to main content
Version: 8.x

Passing parameters to routes

Remember when I said "more on that later when we talk about params!"? Well, the time has come.

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.

Passing params

Params can be passed to screens while navigating to them via various navigation methods such as navigate, push, jumpTo etc. Typically, params are passed as the second argument to these methods.

For example, to pass params while navigating to a screen using navigate:

navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
note

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.

Reading params

Params can be read from the params property of the route object. There are 2 main ways to access the route object:

  1. Your screen component automatically receives the route object as a prop:

    function DetailsScreen({ route }) {
    // Access params from route.params
    const { itemId, otherParam } = route.params;

    return (
    // ...
    );
    }
  2. You can also use the useRoute hook to access the route object in any component inside your screen:

    import { useRoute } from '@react-navigation/native';

    function SomeComponent() {
    const route = useRoute('Details');

    // Access params from route.params
    const { itemId, otherParam } = route.params;

    return (
    // ...
    );
    }

    The useRoute hook takes the name of the current screen or any parent screen as an argument, and returns the route object containing the params for that screen.

In this example, the HomeScreen passes params to the DetailsScreen. The DetailsScreen then reads and displays those params:

function HomeScreen() {
const navigation = useNavigation('Home');

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('Details');

/* 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>
);
}
Try on Snack

Initial params

You can also pass some initial params to a screen. If you didn't specify any params when navigating to this screen, the initial params will be used. They are also shallow merged with any params that you pass. Initial params can be specified in initialParams:

createNativeStackScreen({
Details: {
screen: DetailsScreen,
initialParams: { itemId: 42 },
},
});

Updating params

Screens can also update their params, like they can update their state. There are few ways to do this:

  • setParams - updates the params by merging new params object with existing params
  • replaceParams - replaces the params with new params object
  • pushParams - pushes a new entry in the history stack with the new params object

All of these methods are available on the navigation object and they take a params object as their argument.

Basic usage:

navigation.setParams({
itemId: Math.floor(Math.random() * 100),
})
Try on Snack
note

Avoid using setParams, replaceParams, or pushParams to update screen options such as title etc. If you need to update options, use setOptions instead.

Passing params to a previous screen

Params aren't only useful for passing some data to a new screen, but they can also be useful to pass data to a previous screen as well. For example, let's say you have a screen with a "Create post" button, and the button opens a new screen to create a post. After creating the post, you want to pass the data for the post back to the previous screen.

To achieve this, you can use the popTo method to go back to the previous screen as well as pass params to it:

function HomeScreen({ route }) {
const navigation = useNavigation('Home');

// 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('CreatePost');
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>
</>
);
}
Try on Snack

Here, after you press "Done", the home screen's route.params will be updated to reflect the post text that you passed in navigate.

Passing params to a nested screen

If you have nested navigators, you need to pass params a bit differently. For example, say you have a navigator inside the More screen and want to pass params to the Settings screen inside that navigator. Then you can pass params as the following:

navigation.navigate('More', {
screen: 'Settings',
params: { userId: 'jane' },
})
Try on Snack

See Nesting navigators for more details on nesting.

Reserved param names

Some param names are reserved by React Navigation as part of the API for nested navigators. The list of the reserved param names are as follows:

  • screen
  • params
  • initial
  • state

You should avoid using these param names in your code unless navigating to a screen containing a nested navigator. Otherwise it will result in unexpected behavior, such as the screen not being able to access the params you passed. If you need to pass data to a nested screen, use a different names for the param.

What should be in params

Params serve two main purposes:

  • Information required to identify and display data on a screen (e.g. id of an object to be displayed on the screen)
  • State specific to a screen (e.g. sort order, filters, page numbers etc. that can also be changed on the screen)

Params should contain the minimal information required to show a screen, nothing more. The actual data (e.g. user objects) should be in a global store or global cache.

You can think of the route object as a URL. The same principles apply to params. Think of visiting a shopping website; when you see product listings, the URL usually contains category name, type of sort, any filters etc., not the actual list of products displayed on the screen.

For example, say if you have a Profile screen. When navigating to it, you might be tempted to pass the user object in the params:

// Don't do this
navigation.navigate('Profile', {
user: {
id: 'jane',
firstName: 'Jane',
lastName: 'Done',
age: 25,
},
});

This looks convenient and lets you access the user objects with route.params.user without any extra work.

However, this is an anti-pattern. There are many reasons why this is a bad idea:

  • The same data is duplicated in multiple places. This can lead to bugs such as the profile screen showing outdated data even if the user object has changed after navigation.
  • Each screen that navigates to the Profile screen now needs to know how to fetch the user object - which increases the complexity of the code.
  • URLs to the screen (browser URL on the web, or deep links on native) will contain the user object. This is problematic:
    1. Since the user object is in the URL, it's possible to pass a random user object representing a user that doesn't exist or has incorrect data in the profile.
    2. If the user object isn't passed or improperly formatted, this could result in crashes as the screen won't know how to handle it.
    3. The URL can become very long and unreadable.

A better way is to pass only the ID of the user in params:

navigation.navigate('Profile', { userId: 'jane' });

Now, you can use the passed userId to grab the user from your global cache or fetch it from the API. Using a library such as React Query can simplify this process since it makes it easy to fetch and cache your data. This approach helps to avoid the problems mentioned above.

Some examples of what should be in params are:

  • IDs such as user id, item id etc., e.g. navigation.navigate('Profile', { userId: 'Jane' })
  • State for sorting, filtering data etc. when you have a list of items, e.g. navigation.navigate('Feeds', { sortBy: 'latest' })
  • Timestamps, page numbers or cursors for pagination, e.g. navigation.navigate('Chat', { beforeTime: 1603897152675 })
  • Data to fill inputs on a screen to compose something, e.g. navigation.navigate('ComposeTweet', { title: 'Hello world!' })

Summary

  • navigate and push accept an optional second argument to let you pass parameters to the route you are navigating to. For example: navigation.navigate('RouteName', { paramName: 'value' }).
  • You can read the params through route.params inside a screen
  • You can update the screen's params with navigation.setParams, navigation.replaceParams or navigation.pushParams
  • Initial params can be passed via the initialParams prop on Screen or in the navigator config
  • State such as sort order, filters etc. should be kept in params so that the state is reflected in the URL and can be shared/bookmarked.
  • Params should contain the least amount of data required to identify a screen; for most cases, this means passing the ID of an object instead of passing a full object.
  • Don't keep application specific data or cached data in params; instead, use a global store or cache.
  • Some param names are reserved by React Navigation and should be avoided