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.
If this was a web browser, we'd be able to write something like this:
<a href="details.html">Go to Details</a>
Or programmatically in 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:
Using Link or Button components
The simplest way to navigate is using the Link component from @react-navigation/native or the Button component from @react-navigation/elements:
- Static
- Dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import { createStaticNavigation } from '@react-navigation/native';
import { createNativeStackNavigator } 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: HomeScreen,
Details: DetailsScreen,
},
});
const Navigation = createStaticNavigation(RootStack);
export default function App() {
return <Navigation />;
}
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } 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 Stack = createNativeStackNavigator();
function RootStack() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<RootStack />
</NavigationContainer>
);
}
The Link and Button components accept a screen prop specifying where to navigate when pressed. On the web, they render as anchor tags (<a>) with proper href attributes.
The built-in Link and Button components have their own styling. To create custom link or button components matching your app's design, see the useLinkProps hook.
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:
- Static
- Dynamic
import * as React from 'react';
import { View, Text } from 'react-native';
import {
createStaticNavigation,
useNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
const navigation = useNavigation();
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
import * as React from 'react';
import { View, Text } from 'react-native';
import {
useNavigation,
NavigationContainer,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { Button } from '@react-navigation/elements';
function HomeScreen() {
const navigation = useNavigation();
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
The useNavigation hook returns the navigation object. We can call navigate with the route name we want to go to.
Calling navigation.navigate with an incorrect route name shows an error in development and does nothing in production.
Navigate to a screen multiple times
What happens if we navigate to Details again while already on the Details screen?
- Static
- Dynamic
function DetailsScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button onPress={() => navigation.navigate('Details')}>
Go to Details... again
</Button>
</View>
);
}
function DetailsScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button onPress={() => navigation.navigate('Details')}>
Go to Details... again
</Button>
</View>
);
}
Tapping "Go to Details... again" does nothing because we're already on that route. The navigate function means "go to this screen" - if you're already there, it does nothing.
Let's say we actually want to add another Details screen. This is common when you pass unique data to each route (more on that when we talk about params!). To do this, use push instead of navigate. This adds another route regardless of the existing navigation history:
- Static
- Dynamic
<Button onPress={() => navigation.push('Details')}>
Go to Details... again
</Button>
<Button onPress={() => navigation.push('Details')}>
Go to Details... again
</Button>
Each push call adds a new route to the stack, while navigate only pushes if you're not already on that route.
Going back
The native stack navigator's header automatically shows a back button when there's a screen to go back to.
You can use navigation.goBack() to trigger going back programmatically from your own buttons:
- Static
- Dynamic
function DetailsScreen() {
const navigation = useNavigation();
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>
);
}
function DetailsScreen() {
const navigation = useNavigation();
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>
);
}
On Android, React Navigation calls goBack() automatically on hardware back button press or back gesture.
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
- Static
- Dynamic
function DetailsScreen() {
const navigation = useNavigation();
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>
);
}
function DetailsScreen() {
const navigation = useNavigation();
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>
);
}
Summary
LinkandButtoncomponents can be used to navigate between screens declaratively.- We can use
useLinkPropsto create our own link components. navigation.navigate('RouteName')pushes a new route to the native stack navigator if you're not already on that route.- We can call
navigation.push('RouteName')as many times as we like and it will continue pushing routes. - The header bar will automatically show a back button, but you can programmatically go back by calling
navigation.goBack(). On Android, the hardware back button just works as expected. - You can go back to an existing screen in the stack with
navigation.popTo('RouteName'), and you can go back to the first screen in the stack withnavigation.popToTop(). - The
navigationobject is available to all screen components with theuseNavigationhook.