React Navigation
React Navigation is the de-facto navigation library. Stacks, tabs, drawers, and modal presentations — declarative routing that feels native, with deep linking baked in.
Stack + tabs + typed params + deep links
EXAMPLE
// npm i @react-navigation/native @react-navigation/native-stack @react-navigation/bottom-tabs
// Plus expo: expo install react-native-screens react-native-safe-area-context
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
// 1) Types for safety
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Post: { postId: string };
};
declare global {
namespace ReactNavigation {
interface RootParamList extends RootStackParamList {}
}
}
const Stack = createNativeStackNavigator<RootStackParamList>();
const Tabs = createBottomTabNavigator();
// 2) Stack inside a Tab
function FeedStack() {
return (
<Stack.Navigator screenOptions={{ headerLargeTitle: true }}>
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Feed' }} />
<Stack.Screen name="Post" component={PostScreen} options={({ route }) => ({ title: `Post #${route.params.postId}` })} />
</Stack.Navigator>
);
}
// 3) The Root
export default function App() {
return (
<NavigationContainer linking={linking}>
<Tabs.Navigator>
<Tabs.Screen name="FeedTab" component={FeedStack} options={{ title: 'Feed' }} />
<Tabs.Screen name="ProfileTab" component={ProfileStack} options={{ title: 'Me' }} />
</Tabs.Navigator>
</NavigationContainer>
);
}
// 4) Navigate from a screen
import { useNavigation, useRoute } from '@react-navigation/native';
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
type Props = NativeStackScreenProps<RootStackParamList, 'Home'>;
function HomeScreen({ navigation }: Props) {
return (
<Button title="Open post" onPress={() => navigation.navigate('Post', { postId: 'p_42' })} />
);
}
function PostScreen({ route, navigation }: NativeStackScreenProps<RootStackParamList, 'Post'>) {
const { postId } = route.params;
return <Text>Post {postId}</Text>;
}
// 5) Modal presentation — bottom-sheet on iOS-style
<Stack.Group screenOptions={{ presentation: 'modal' }}>
<Stack.Screen name="Compose" component={ComposeScreen} />
</Stack.Group>
// 6) Deep linking config
const linking = {
prefixes: ['myapp://', 'https://app.example.com'],
config: {
screens: {
FeedTab: {
screens: {
Home: 'feed',
Post: 'post/:postId',
},
},
ProfileTab: 'me',
},
},
};
// myapp://post/p_42 → Post screen with params: { postId: 'p_42' }
// 7) Use the focus hook — refetch when the user lands back
import { useFocusEffect } from '@react-navigation/native';
useFocusEffect(
React.useCallback(() => {
refetchData();
return () => {};
}, [])
);
// 8) Drawer (optional)
import { createDrawerNavigator } from '@react-navigation/drawer';
const Drawer = createDrawerNavigator();
Why it matters
Define a typed param list once and let TypeScript carry it through every screen. Mistyping a route name or forgetting a param becomes a compile error, not a runtime crash.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Install npm install @react-navigation/native @react-navigation/native-stack npm install react-native-screens react-native-safe-area-contextTry it Yourself »
Exercise
Root navigator wrapper component.
<
>{…}</
>
PascalCase.
Discussion
Loading…