Wat is Expo Router?

Expo Router is een file-based router voor React Native. Dit betekent dat je mappenstructuur automatisch je app navigatie bepaalt!

Voordelen van Expo Router:

  • File-based: Mappen = routes, geen handmatige configuratie
  • Type-safe: Automatische TypeScript types voor routes
  • Native: Werkt perfect op iOS en Android
  • Deep linking: URLs werken automatisch

Hoe werkt het?

Elke .jsx of .tsx file in de app/ map wordt automatisch een route!

  • app/index.jsx/ (home pagina)
  • app/about.jsx/about
  • app/profile/settings.jsx/profile/settings

Installatie

Installeer Expo Router in je project:

npx expo install expo-router

Let op: Als je een nieuw project start met npx create-expo-app@latest, is Expo Router al geïnstalleerd!

Mappenstructuur

Een typische Expo Router app ziet er zo uit:

app/
├── _layout.jsx           (Hoofd Stack Navigator)
├── index.jsx             (Startscherm)
├── +not-found.jsx        (404 pagina)
├── screens/
│   ├── tabs/
│   │   ├── _layout.jsx   (Bottom Tabs)
│   │   ├── home.jsx      (Home tab)
│   │   └── profile.jsx   (Profile tab)
│   ├── details.jsx
│   └── auth/
│       ├── login.jsx
│       └── register.jsx

Belangrijk:

  • _layout.jsx = speciale file voor navigatie configuratie
  • +not-found.jsx = fallback voor niet-bestaande routes
  • Mappen zonder _layout.jsx worden gewone routes

Stack Navigator

De Stack Navigator laat je van scherm naar scherm navigeren. Elk scherm wordt "bovenop" de vorige geplaatst.

Hoofd Layout

In app/_layout.jsx configureer je de Stack:

import { Stack } from 'expo-router';

export default function Layout() {
  return (
    <Stack screenOptions={{ headerShown: false }}>
      <Stack.Screen name="index" />
      <Stack.Screen name="screens/auth/login" />
      <Stack.Screen name="screens/auth/register" />
      <Stack.Screen name="screens/tabs" />
    </Stack>
  );
}

Uitleg:

  • Stack = de navigator component
  • screenOptions = instellingen voor alle schermen
  • headerShown: false = verberg de standaard header
  • Stack.Screen = registreer een scherm
  • name = pad naar het bestand (zonder .jsx)

Startscherm

In app/index.jsx maak je het eerste scherm:

import { View, Text, Pressable, StyleSheet } from 'react-native';
import { useRouter } from 'expo-router';

export default function WelcomeScreen() {
  const router = useRouter();

  return (
    <View style={styles.container}>
      <Text style={styles.title}>Welkom!</Text>
      
      <Pressable 
        style={styles.button}
        onPress={() => router.push('/screens/auth/login')}
      >
        <Text style={styles.buttonText}>Inloggen</Text>
      </Pressable>

      <Pressable 
        style={styles.button}
        onPress={() => router.replace('/screens/tabs/home')}
      >
        <Text style={styles.buttonText}>Verder naar de app</Text>
      </Pressable>
    </View>
  );
}

Bottom Tabs

Bottom Tabs zijn de navigatiebalk onderaan je app, zoals in Instagram of Twitter.

Tabs Layout

In app/screens/tabs/_layout.jsx:

import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function TabsLayout() {
  return (
    <Tabs
      screenOptions={{
        headerShown: false,
        tabBarLabel: () => null,
        tabBarStyle: {
          height: 80,
          paddingBottom: 5,
          paddingTop: 10,
        },
      }}
    >
      <Tabs.Screen
        name="home"
        options={{
          title: 'Home',
          tabBarIcon: () => (
            <Ionicons name="home-outline" size={24} color="black" />
          ),
        }}
      />

      <Tabs.Screen
        name="profile"
        options={{
          title: 'Profile',
          tabBarIcon: () => (
            <Ionicons name="person-outline" size={24} color="black" />
          ),
        }}
      />
    </Tabs>
  );
}

Tab Schermen

In app/screens/tabs/home.jsx:

import { View, Text, StyleSheet } from 'react-native';

export default function HomeScreen() {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Home Pagina</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
    fontSize: 24,
    fontWeight: 'bold',
  },
});

Icons Toevoegen

Voor tab icons gebruik je @expo/vector-icons (al geïnstalleerd met Expo).

Ionicons Gebruiken

import { Ionicons } from '@expo/vector-icons';

<Tabs.Screen
  name="home"
  options={{
    tabBarIcon: ({ focused, color, size }) => (
      <Ionicons 
        name={focused ? 'home' : 'home-outline'} 
        size={24} 
        color={color} 
      />
    ),
  }}
/>

Actieve vs Inactieve Icons

<Tabs
  screenOptions={{
    tabBarActiveTintColor: '#007AFF',
    tabBarInactiveTintColor: '#8E8E93',
  }}
>
  <Tabs.Screen
    name="home"
    options={{
      tabBarIcon: ({ focused, color }) => (
        <Ionicons 
          name={focused ? 'home' : 'home-outline'}
          size={24}
          color={color}
        />
      ),
    }}
  />

  <Tabs.Screen
    name="profile"
    options={{
      tabBarIcon: ({ focused, color }) => (
        <Ionicons 
          name={focused ? 'person' : 'person-outline'}
          size={24}
          color={color}
        />
      ),
    }}
  />
</Tabs>

Populaire Ionicons:

home / home-outline
search / search-outline
heart / heart-outline
person / person-outline
settings / settings-outline
notifications / notifications-outline
add-circle / add-circle-outline
star / star-outline

Bekijk alle icons op: https://icons.expo.fyi

404 Pagina

Als een gebruiker naar een niet-bestaande route gaat, wordt de +not-found.jsx pagina getoond.

Not Found Pagina

In app/+not-found.jsx:

import { View, Text, Pressable, StyleSheet } from 'react-native';
import { useRouter } from 'expo-router';

export default function NotFoundScreen() {
  const router = useRouter();

  return (
    <View style={styles.container}>
      <Text style={styles.emoji}>🚫</Text>
      <Text style={styles.title}>Pagina niet gevonden</Text>
      <Text style={styles.subtitle}>Deze pagina bestaat niet</Text>
      
      <Pressable 
        style={styles.button}
        onPress={() => router.replace('/')}
      >
        <Text style={styles.buttonText}>Terug naar Home</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  emoji: {
    fontSize: 80,
    marginBottom: 20,
  },
  title: {
    fontSize: 28,
    fontWeight: 'bold',
    marginBottom: 10,
  },
  subtitle: {
    fontSize: 16,
    color: '#666',
    marginBottom: 30,
  },
  button: {
    backgroundColor: '#007AFF',
    padding: 15,
    borderRadius: 8,
    minWidth: 200,
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
    textAlign: 'center',
  },
});

Tip: Gebruik altijd router.replace('/') in je 404 pagina, zodat gebruikers niet terug kunnen naar de foutpagina.

Samenvatting

File-based

Mappenstructuur = routes

_layout.jsx

Stack of Tabs configuratie

router.push()

Met terug knop

router.replace()

Zonder terug knop

Je hebt nu geleerd:

  • Hoe Expo Router werkt met file-based routing
  • Stack Navigator instellen voor scherm-naar-scherm navigatie
  • Bottom Tabs maken voor navigatiebalk onderaan
  • Navigeren met push(), replace() en back()
  • Icons toevoegen aan tabs met Ionicons
  • 404 pagina maken voor niet-bestaande routes