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/profileGroupes 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 → /profileLe 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>
);
}Navigation
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>
);
}