iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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-context
Try it Yourself »

Exercise

Root navigator wrapper component.

< >{…}</ >

Test yourself

Q1. The de-facto routing lib is…
Q2. A back-button stack typically uses…
Q3. Bottom tabs typically use…

Discussion

Loading…