Expo Router pour React Native : Guide Complet de la Navigation par Fichiers
Expo Router apporte le routage basé sur les fichiers à React Native, inspiré de Next.js. Guide complet avec configuration, navigation par onglets, routes dynamiques, modales, middleware et protection des routes.

Expo Router transforme la gestion de la navigation dans les applications React Native en adoptant un système de routage basé sur les fichiers, directement inspiré de Next.js. Avec le SDK Expo 55 et Expo Router v6, la configuration manuelle des navigateurs appartient au passé. Il suffit de créer un fichier dans le répertoire app pour qu'un écran devienne accessible. Android, iOS et le web sont pris en charge de manière unifiée, sans configuration supplémentaire. Cette approche réduit considérablement la complexité des projets multiplateforme et accélère le développement mobile.
Les nouveaux projets Expo intègrent Expo Router par défaut. La commande npx create-expo-app@latest --template default@sdk-55 génère un projet préconfiguré avec le routage par fichiers. Pour les projets existants, il suffit d'installer le package expo-router et de mettre à jour le point d'entrée de l'application.
Fonctionnement du routage par fichiers dans Expo Router
Chaque fichier placé dans le répertoire app devient automatiquement une route. Le chemin du fichier correspond directement au chemin de l'URL, ce qui élimine toute nécessité d'un fichier de configuration centralisé. Un fichier app/settings.tsx crée la route /settings, tandis que app/profile/edit.tsx correspond à /profile/edit.
Cette convention offre trois avantages majeurs par rapport à la configuration traditionnelle avec React Navigation :
- Zéro configuration : les routes existent dès la création du fichier
- Deep linking automatique : chaque écran dispose d'une URL, facilitant le partage et les tests
- Navigation typée : TypeScript connaît les routes existantes dès la compilation
import { View, Text, StyleSheet } from 'react-native'
import { Link } from 'expo-router'
export default function HomeScreen() {
return (
<View style={styles.container}>
<Text style={styles.title}>Welcome</Text>
{/* Link maps directly to file path */}
<Link href="/settings" style={styles.link}>
Open Settings
</Link>
<Link href="/profile/edit" style={styles.link}>
Edit Profile
</Link>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', padding: 24 },
title: { fontSize: 28, fontWeight: 'bold', marginBottom: 16 },
link: { fontSize: 16, color: '#61DAFB', marginTop: 12 },
})Le composant Link gère la navigation sur toutes les plateformes. Sur le web, il génère une balise ancre avec les attributs href appropriés pour le référencement. Sur les plateformes natives, il déclenche une navigation de type stack.
Structure du projet et fichiers de layout
Expo Router utilise des fichiers _layout.tsx pour définir les conteneurs de navigation. Chaque répertoire peut contenir son propre layout, créant ainsi des hiérarchies de navigation imbriquées. Le layout racine enveloppe l'ensemble de l'application, tandis que les layouts imbriqués contrôlent des sections spécifiques.
Voici une structure de projet typique :
app/
_layout.tsx # Root layout (Stack or custom)
index.tsx # Home screen (/)
(tabs)/ # Tab group (parentheses = route group)
_layout.tsx # Tab navigator
home.tsx # /home tab
search.tsx # /search tab
profile.tsx # /profile tab
settings/
_layout.tsx # Settings stack layout
index.tsx # /settings
notifications.tsx # /settings/notifications
privacy.tsx # /settings/privacyLes groupes de routes -- des répertoires entourés de parenthèses -- organisent les fichiers sans affecter l'URL. Le répertoire (tabs) ci-dessus crée un navigateur par onglets, mais les URL restent /home, /search et /profile plutôt que /tabs/home.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack
screenOptions={{
headerStyle: { backgroundColor: '#1a1a2e' },
headerTintColor: '#ffffff',
headerTitleStyle: { fontWeight: '600' },
}}
>
<Stack.Screen name="index" options={{ title: 'Home' }} />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="settings" options={{ title: 'Settings' }} />
</Stack>
)
}Le layout racine sert également de point d'initialisation pour le chargement des polices, la configuration des providers et les réglages globaux. Il remplace le traditionnel App.tsx comme point d'entrée de l'application.
Construction d'une navigation par onglets
La navigation par onglets nécessite un fichier _layout.tsx à l'intérieur d'un groupe de routes. Expo Router v6 introduit NativeTabs pour des expériences natives spécifiques à chaque plateforme, mais le composant standard Tabs couvre la plupart des cas d'utilisation.
import { Tabs } from 'expo-router'
import { Ionicons } from '@expo/vector-icons'
export default function TabLayout() {
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: '#61DAFB',
tabBarInactiveTintColor: '#888',
tabBarStyle: {
backgroundColor: '#1a1a2e',
borderTopColor: '#2d2d44',
},
}}
>
<Tabs.Screen
name="home"
options={{
title: 'Home',
tabBarIcon: ({ color, size }) => (
<Ionicons name="home" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="search"
options={{
title: 'Search',
tabBarIcon: ({ color, size }) => (
<Ionicons name="search" size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profile',
tabBarIcon: ({ color, size }) => (
<Ionicons name="person" size={size} color={color} />
),
}}
/>
</Tabs>
)
}Chaque fichier d'écran d'onglet exporte un composant React standard. L'icône, le libellé et le badge de la barre d'onglets se configurent via la prop options du layout.
Routes dynamiques et paramètres de route
Les segments dynamiques utilisent des crochets dans le nom du fichier. Un fichier nommé [id].tsx correspond à un segment unique, tandis que [...slug].tsx capture tous les segments restants du chemin.
import { View, Text, StyleSheet } from 'react-native'
import { useLocalSearchParams, Stack } from 'expo-router'
export default function ProductScreen() {
// Extract the dynamic parameter from the URL
const { id } = useLocalSearchParams<{ id: string }>()
return (
<View style={styles.container}>
<Stack.Screen options={{ title: `Product ${id}` }} />
<Text style={styles.heading}>Product Details</Text>
<Text style={styles.id}>ID: {id}</Text>
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 24 },
heading: { fontSize: 24, fontWeight: 'bold', marginBottom: 8 },
id: { fontSize: 16, color: '#888' },
})Accéder à /product/42 affiche cet écran avec la variable id définie sur "42". Le hook useLocalSearchParams fournit un accès typé à l'ensemble des paramètres de route.
Pour les routes attrape-tout, [...slug].tsx capture des segments de chemin entiers :
import { useLocalSearchParams } from 'expo-router'
export default function DocsScreen() {
// /docs/getting-started/installation → slug = ['getting-started', 'installation']
const { slug } = useLocalSearchParams<{ slug: string[] }>()
return <DocViewer path={slug.join('/')} />
}Prêt à réussir tes entretiens React Native ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
Typage des routes pour une sécurité à la compilation
Expo Router génère automatiquement les types de routes lorsque la fonctionnalité typed routes est activée. Cette vérification détecte les liens cassés à la compilation plutôt qu'à l'exécution.
Activation dans le fichier app.json :
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}Une fois activé, la prop href du composant Link et l'argument de router.push() n'acceptent que des chaînes correspondant à des routes valides :
import { router } from 'expo-router'
function handleCheckout(cartId: string) {
// TypeScript validates this route exists
router.push(`/product/${cartId}`)
// This would cause a compile error if /nonexistent doesn't exist
// router.push('/nonexistent')
}Le typage des routes fonctionne particulièrement bien avec useLocalSearchParams. Les types générés garantissent la correspondance entre les noms de paramètres dans la définition de la route et ceux utilisés par le composant consommateur, prévenant ainsi les bugs subtils qui ne se manifestent qu'à la navigation vers un écran spécifique.
Écrans modaux et options de présentation
Les modales dans Expo Router sont des écrans classiques configurés avec presentation: 'modal' dans le layout. Cette approche respecte la convention du routage par fichiers : une modale reste simplement une route comme les autres.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
{/* Modal screen slides up from the bottom */}
<Stack.Screen
name="create-post"
options={{
presentation: 'modal',
headerTitle: 'New Post',
}}
/>
</Stack>
)
}import { View, TextInput, Button, StyleSheet } from 'react-native'
import { router } from 'expo-router'
import { useState } from 'react'
export default function CreatePostModal() {
const [title, setTitle] = useState('')
const handleSubmit = () => {
// Submit logic here
router.back() // Dismiss the modal
}
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="Post title"
value={title}
onChangeText={setTitle}
/>
<Button title="Publish" onPress={handleSubmit} />
</View>
)
}
const styles = StyleSheet.create({
container: { flex: 1, padding: 24 },
input: {
borderWidth: 1,
borderColor: '#333',
borderRadius: 8,
padding: 12,
fontSize: 16,
marginBottom: 16,
},
})Accéder à /create-post déclenche la présentation modale. L'appel à router.back() la ferme et ramène l'utilisateur à l'écran précédent dans la pile de navigation.
Navigation programmatique et API du routeur
Au-delà du composant Link, Expo Router fournit une API impérative via l'objet router. Celle-ci permet de gérer la navigation déclenchée par la logique métier plutôt que par une interaction directe de l'utilisateur.
import { router } from 'expo-router'
// Push a new screen onto the stack
router.push('/profile/settings')
// Replace the current screen (no back button)
router.replace('/login')
// Go back to the previous screen
router.back()
// Navigate with parameters
router.push({
pathname: '/product/[id]',
params: { id: '42', source: 'recommendations' },
})
// Check if going back is possible
import { useRouter } from 'expo-router'
function BackButton() {
const router = useRouter()
return router.canGoBack() ? (
<Button title="Back" onPress={() => router.back()} />
) : null
}La distinction entre router.push et router.replace est essentielle dans les flux d'authentification. Après une connexion réussie, router.replace('/dashboard') empêche l'utilisateur de revenir à l'écran de connexion via le bouton retour.
router.replace() remplace l'entrée courante dans l'historique de navigation. Pour les gardes d'authentification qui redirigent les utilisateurs non connectés, il est préférable d'utiliser <Redirect href="/login" /> dans le rendu du composant. Ce dernier se déclenche pendant la phase de rendu et fonctionne correctement avec le rendu côté serveur sur le web.
Middleware et protection des routes
Expo Router v6 introduit le middleware serveur pour la logique appliquée au niveau des routes. Le fichier +middleware.ts intercepte les requêtes avant qu'elles n'atteignent le composant de la route, permettant ainsi des vérifications d'authentification, des redirections et la manipulation des en-têtes HTTP.
import { type MiddlewareRequest } from 'expo-router/server'
export function middleware(request: MiddlewareRequest) {
const { pathname } = request.nextUrl
// Protect dashboard routes
const protectedPaths = ['/dashboard', '/settings', '/profile']
const isProtected = protectedPaths.some(p => pathname.startsWith(p))
if (isProtected) {
const token = request.cookies.get('session')
if (!token) {
return Response.redirect(new URL('/login', request.url))
}
}
return undefined // Continue to route
}Sur les plateformes natives, le middleware serveur ne s'exécute pas. La protection des routes repose alors sur des gardes côté client. Le pattern le plus courant consiste à envelopper les layouts protégés d'une vérification d'authentification :
import { Redirect, Stack } from 'expo-router'
import { useAuth } from '@/hooks/useAuth'
export default function AuthenticatedLayout() {
const { isLoggedIn, isLoading } = useAuth()
if (isLoading) return null
if (!isLoggedIn) return <Redirect href="/login" />
return <Stack />
}Le middleware serveur ne s'exécute que sur le web avec le rendu côté serveur. Pour les applications natives, il est impératif d'implémenter des gardes côté client dans les composants de layout. Combiner les deux approches garantit une protection cohérente sur l'ensemble des plateformes.
Conclusion
Expo Router v6 apporte à l'écosystème React Native une approche de la navigation qui aligne le développement mobile sur les conventions établies par les frameworks web modernes. Les points essentiels à retenir :
- Expo Router v6 remplace la configuration manuelle de la navigation par des conventions basées sur les fichiers, chaque fichier du répertoire
appdevenant automatiquement une route - Les layouts définis via les fichiers
_layout.tsxcréent des hiérarchies de navigation -- stacks, onglets et drawers -- sans fichier de configuration centralisé - Les routes dynamiques avec
[param].tsxet les routes attrape-tout avec[...slug].tsxgèrent la navigation paramétrée avec un support TypeScript complet - Le typage des routes détecte les liens de navigation cassés à la compilation lorsque la fonctionnalité est activée dans
app.json - Les écrans modaux, la navigation programmatique via
router.push/replace/backet le middleware serveur complètent la boîte à outils du routage - Les groupes de routes par répertoires entre parenthèses organisent le code sans affecter les URL, maintenant une arborescence lisible à mesure que l'application grandit
- Les gardes côté client dans les layouts gèrent l'authentification sur le natif, tandis que le middleware serveur couvre le web -- combiner les deux garantit une couverture multiplateforme
Passe à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Tags
Partager
Articles similaires

React Native vs Flutter : Comparatif complet 2026
Comparaison détaillée React Native vs Flutter en 2026 : performances, architecture, DX, coûts. Guide pour choisir le bon framework cross-platform.

Top 30 questions d'entretien React Native : guide complet 2026
Les 30 questions d'entretien React Native les plus posées. Réponses détaillées avec exemples de code pour décrocher votre poste de développeur mobile.

React Native : Créer une app mobile complète en 2026
Guide complet pour développer une application mobile iOS et Android avec React Native. De la configuration à la publication, tous les fondamentaux pour démarrer.