ScaleRocket/Mobile

Expo Router

Plongée approfondie dans le routage basé sur les fichiers avec groupes de routes, layouts, stack vs onglets, routes typées et liaison.

Expo Router

ScaleRocket Mobile utilise Expo Router pour le routage basé sur les fichiers. Chaque fichier dans le répertoire app/ devient automatiquement un écran navigable.

Comment ça marche

Expo Router associe les fichiers aux routes :

app/
├── index.tsx          →  /
├── about.tsx          →  /about
├── settings/
│   ├── index.tsx      →  /settings
│   └── profile.tsx    →  /settings/profile

Groupes de routes

Les parenthèses () créent des groupes qui partagent un layout sans affecter l'URL :

app/
├── (auth)/
│   ├── _layout.tsx    # Navigateur stack pour les écrans d'auth
│   ├── login.tsx      →  /login
│   └── register.tsx   →  /register
├── (tabs)/
│   ├── _layout.tsx    # Navigateur par onglets pour l'app principale
│   ├── index.tsx      →  /
│   └── profile.tsx    →  /profile

Le nom du groupe (auth) n'apparaît pas dans l'URL. /login est la route, pas /(auth)/login.

Layouts

Chaque fichier _layout.tsx définit la structure de navigation pour son répertoire :

Layout Stack (Auth)

// app/(auth)/_layout.tsx
import { Stack } from "expo-router";

export default function AuthLayout() {
  return (
    <Stack screenOptions={{ headerShown: false }}>
      <Stack.Screen name="login" />
      <Stack.Screen name="register" />
      <Stack.Screen name="forgot-password" />
    </Stack>
  );
}

Layout Onglets (App principale)

// app/(tabs)/_layout.tsx
import { Tabs } from "expo-router";
import { Ionicons } from "@expo/vector-icons";

export default function TabLayout() {
  return (
    <Tabs screenOptions={{ headerShown: false }}>
      <Tabs.Screen
        name="index"
        options={{
          title: "Home",
          tabBarIcon: ({ color, size }) => (
            <Ionicons name="home" size={size} color={color} />
          ),
        }}
      />
      <Tabs.Screen
        name="profile"
        options={{
          title: "Profile",
          tabBarIcon: ({ color, size }) => (
            <Ionicons name="person" size={size} color={color} />
          ),
        }}
      />
    </Tabs>
  );
}

Utilisez l'objet router ou le composant Link :

import { router } from "expo-router";
import { Link } from "expo-router";

// Navigation programmatique
router.push("/profile");
router.replace("/login");    // Remplacer l'écran courant (pas de retour)
router.back();               // Retour

// Navigation déclarative
<Link href="/profile">
  <Text>Go to Profile</Text>
</Link>

Routes dynamiques

Les crochets [] créent des segments dynamiques :

app/
├── user/
│   └── [id].tsx       →  /user/123
// app/user/[id].tsx
import { useLocalSearchParams } from "expo-router";

export default function UserScreen() {
  const { id } = useLocalSearchParams<{ id: string }>();
  return <Text>User ID: {id}</Text>;
}

Routes typées

Activez les routes typées dans app.json pour l'autocomplétion :

{
  "expo": {
    "experiments": {
      "typedRoutes": true
    }
  }
}

Après activation, TypeScript autocomplète les chemins de route :

router.push("/profile");   // ✓ Route valide
router.push("/nonexist");  // ✗ Erreur de type

Écrans modaux

Présentez des écrans comme des modaux :

// app/_layout.tsx
<Stack>
  <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
  <Stack.Screen
    name="modal"
    options={{ presentation: "modal", headerTitle: "Modal" }}
  />
</Stack>
// Naviguer vers le modal depuis n'importe où
router.push("/modal");

Deep Linking

Expo Router gère les deep links automatiquement. Configurez votre schéma dans app.json :

{
  "expo": {
    "scheme": "scalerocket"
  }
}

L'URL scalerocket:///profile ouvre l'écran de profil. Consultez le guide Deep Linking pour la configuration complète.

Écran non trouvé

Ajoutez un écran pour les routes non trouvées :

// app/+not-found.tsx
export default function NotFound() {
  return (
    <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
      <Text>Page not found</Text>
      <Link href="/">Go home</Link>
    </View>
  );
}

On this page