Skip to main content
Version: 8.x

Moving between screens

In the previous section, we defined a stack navigator with two routes (Home and Details), but we didn't learn how to let a user navigate from Home to Details (although we did learn how to change the initial route in our code, but forcing our users to clone our repository and change the route in our code in order to see another screen is arguably among the worst user experiences one could imagine).

If this was a web browser, we'd be able to write something like this:

<a href="details.html">Go to Details</a>

It's also possible to programmatically change the URL using JavaScript:

window.location.href = 'details.html';

So how do we do this in React Navigation? There are two main ways to navigate between screens in React Navigation:

The simplest way to navigate is by using the Link component from @react-navigation/native or the Button component from @react-navigation/elements:

import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
import {
createNativeStackNavigator,
createNativeStackScreen,
} from '@react-navigation/native-stack';
import { Link } from '@react-navigation/native';
import { Button } from '@react-navigation/elements';

function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Link screen="Details">Go to Details</Link>
<Button screen="Details">Go to Details</Button>
</View>
);
}

function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}

const RootStack = createNativeStackNavigator({
initialRouteName: 'Home',
screens: {
Home: createNativeStackScreen({
screen: HomeScreen,
}),
Details: createNativeStackScreen({
screen: DetailsScreen,
}),
},
});

const Navigation = createStaticNavigation(RootStack);

export default function App() {
return <Navigation />;
}
Try on Snack

Let's break this down:

  • The Link and Button components accept a screen prop that specifies the name of the screen to navigate to when pressed.
  • When the user taps on the Link or Button, React Navigation automatically navigates to the specified screen.

When using on the web, they also render as anchor tags (<a>) with href attribute, which is essential to preserve native browser behaviors like "Right click → Open link in new tab".

note

The built-in Link and Button components come with their own styling. But it's likely that you'll want to create your own custom link or button component to match your app's design. See useLinkProps hook on how to create custom link components.

Using the navigation object

Another way to navigate is by using the navigation object. This method gives you more control over when and how navigation happens.

The navigation object is available in your screen components through the useNavigation hook:

import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
import {
createNativeStackNavigator,
createNativeStackScreen,
} from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';

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

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button onPress={() => navigation.navigate('Details')}>
Go to Details
</Button>
</View>
);
}

// ... other code from the previous section
Try on Snack

Let's break this down:

  • The navigation object is returned from the useNavigation hook - it takes the name of the current route as an argument (in this case, Home).
  • We call the navigate function (on the navigation object — naming is hard!) with the name of the route that we'd like to move the user to.
note

If you call navigation.navigate with a route name that you haven't defined in your navigator, you'll see an error in development builds and nothing will happen in production builds. You can only navigate to routes that have been defined in your navigator.

So we now have a stack with two routes: the Home route and the Details route. What would happen if we navigated to the Details route again from the Details screen?

function DetailsScreen() {
const navigation = useNavigation('Details');

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button onPress={() => navigation.navigate('Details')}>
Go to Details... again
</Button>
</View>
);
}
Try on Snack

If you run this code, you'll notice that when you tap "Go to Details... again", it doesn't do anything! This is because we are already on the Details route. The navigate function roughly means "go to this screen", and if you are already on that screen then it makes sense that it would do nothing.

Let's suppose that we actually want to add another details screen. This is pretty common in cases where you pass in some unique data to each route (more on that later when we talk about params!). To do this, we can change navigate to push. This allows us to express the intent to add another route regardless of the existing navigation history.

<Button onPress={() => navigation.push('Details')}>
Go to Details... again
</Button>
Try on Snack

Each time you call push we add a new route to the navigation stack. When you call navigate it only pushes a new route if you're not already on that route.

Going back

The header provided by the native stack navigator will automatically include a back button when it is possible to go back from the active screen (if there is only one screen in the navigation stack, there is nothing that you can go back to, and so there is no back button).

Sometimes you'll want to be able to programmatically trigger this behavior, and for that, you can use navigation.goBack().

function DetailsScreen() {
const navigation = useNavigation('Details');

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button onPress={() => navigation.push('Details')}>
Go to Details... again
</Button>
<Button onPress={() => navigation.goBack()}>Go back</Button>
</View>
);
}
Try on Snack
note

On Android, React Navigation hooks into the hardware back button and automatically calls goBack() when the user presses it, so it behaves as expected.

Sometimes you need to go back multiple screens at once. For example, if you're several screens deep in a stack and want to go back to the first screen. You have two options:

  • navigation.popTo('Home') - Go back to a specific screen (in this case, Home)
  • navigation.popToTop() - Go back to the first screen in the stack
function DetailsScreen() {
const navigation = useNavigation('Details');

return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button onPress={() => navigation.push('Details')}>
Go to Details... again
</Button>
<Button onPress={() => navigation.goBack()}>Go back</Button>
<Button onPress={() => navigation.popTo('Home')}>Go to Home</Button>
<Button onPress={() => navigation.popToTop()}>
Go back to first screen in stack
</Button>
</View>
);
}
Try on Snack

Summary