Expo Router in React Native: Guida Completa alla Navigazione File-Based
Guida completa a Expo Router per React Native nel 2026. Navigazione basata su file, route dinamiche, tab, modali, typed routes, middleware e protezione delle route con esempi di codice.

Expo Router ridefinisce la gestione della navigazione nelle applicazioni React Native, sostituendo la configurazione manuale dei navigatori con un sistema di routing basato sulla struttura dei file. Ispirato a framework web come Next.js, ogni file all'interno della directory app/ diventa automaticamente una route accessibile. Con l'SDK Expo 55 e Expo Router v6, la dichiarazione esplicita degli stack di navigazione appartiene al passato. Android, iOS e web vengono gestiti in modo unificato, senza configurazioni aggiuntive per ciascuna piattaforma. Questo approccio riduce drasticamente la complessità dei progetti multipiattaforma e accelera i cicli di sviluppo mobile.
I nuovi progetti Expo integrano Expo Router per impostazione predefinita. Il comando npx create-expo-app@latest --template default@sdk-55 genera un progetto preconfigurato con il routing file-based. Per i progetti esistenti, e sufficiente installare il pacchetto expo-router e aggiornare il punto di ingresso dell'applicazione.
Come funziona il routing basato su file in Expo Router
Ogni file inserito nella directory app/ si trasforma automaticamente in una route. Il percorso del file corrisponde direttamente al percorso dell'URL, eliminando la necessita di un file di configurazione centralizzato. Un file app/settings.tsx genera la route /settings, mentre app/profile/edit.tsx corrisponde a /profile/edit.
Questa convenzione offre tre vantaggi fondamentali rispetto alla configurazione tradizionale con React Navigation:
- Zero configurazione: le route esistono nel momento stesso in cui il file viene creato
- Deep linking automatico: ogni schermata dispone di un URL, semplificando la condivisione e il testing
- Navigazione tipizzata: TypeScript conosce le route esistenti gia in fase di compilazione
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 },
})Il componente Link gestisce la navigazione su tutte le piattaforme. Sul web, genera un tag anchor con gli attributi href appropriati per l'indicizzazione nei motori di ricerca. Sulle piattaforme native, attiva una navigazione di tipo stack con le transizioni previste dal sistema operativo.
Struttura del progetto e file di layout
Expo Router utilizza file _layout.tsx per definire i contenitori di navigazione. Ogni directory puo contenere il proprio layout, creando gerarchie di navigazione annidate. Il layout radice avvolge l'intera applicazione, mentre i layout annidati controllano sezioni specifiche.
Una struttura di progetto tipica si presenta nel modo seguente:
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/privacyI gruppi di route -- directory racchiuse tra parentesi -- organizzano i file senza influire sull'URL. La directory (tabs) nell'esempio precedente crea un navigatore a schede, ma gli URL rimangono /home, /search e /profile anziche /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>
)
}Il layout radice funge anche da punto di inizializzazione per il caricamento dei font, la configurazione dei provider e le impostazioni globali. Sostituisce il tradizionale App.tsx come punto di ingresso dell'applicazione.
Costruzione di una navigazione a schede
La navigazione a schede rappresenta uno dei pattern piu diffusi nelle applicazioni mobile. Expo Router ne semplifica l'implementazione tramite il componente Tabs, configurabile direttamente nel file _layout.tsx del gruppo di route corrispondente.
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>
)
}Ogni file di schermata all'interno del gruppo di schede esporta un componente React standard. L'icona, l'etichetta e il badge della barra delle schede si configurano attraverso la prop options del layout. L'ordine di dichiarazione nel file _layout.tsx determina la sequenza delle schede nella barra di navigazione.
Route dinamiche e parametri di route
I segmenti dinamici utilizzano le parentesi quadre nel nome del file. Un file denominato [id].tsx cattura un singolo segmento dell'URL, mentre [...slug].tsx intercetta tutti i segmenti rimanenti del percorso.
import { View, Text, StyleSheet } from 'react-native'
import { useLocalSearchParams, Stack } from 'expo-router'
export default function ProductScreen() {
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' },
})Navigando verso /product/42, la schermata viene visualizzata con la variabile id impostata su "42". L'hook useLocalSearchParams fornisce un accesso tipizzato a tutti i parametri della route.
Per le route catch-all, la sintassi [...slug].tsx consente di catturare interi segmenti di percorso:
import { useLocalSearchParams } from 'expo-router'
export default function DocsScreen() {
const { slug } = useLocalSearchParams<{ slug: string[] }>()
return <DocViewer path={slug.join('/')} />
}Le route catch-all catturano tutti i segmenti restanti dell'URL in un array. La route /docs/getting-started/installation produce un array ['getting-started', 'installation'] che il componente puo utilizzare per il rendering del contenuto corrispondente.
Pronto a superare i tuoi colloqui su React Native?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
Tipizzazione delle route per la sicurezza in fase di compilazione
Uno dei problemi ricorrenti nella navigazione mobile riguarda il passaggio di route come stringhe di testo prive di qualsiasi verifica a tempo di compilazione. Expo Router risolve questa criticita con le typed routes, una funzionalita che genera automaticamente i tipi TypeScript a partire dalla struttura dei file.
L'attivazione avviene nel file app.json:
{
"expo": {
"experiments": {
"typedRoutes": true
}
}
}Una volta attivata, la prop href del componente Link e l'argomento di router.push() accettano esclusivamente stringhe corrispondenti a route valide:
import { router } from 'expo-router'
function handleCheckout(cartId: string) {
router.push(`/product/${cartId}`)
}La tipizzazione delle route funziona particolarmente bene con useLocalSearchParams. I tipi generati garantiscono la corrispondenza tra i nomi dei parametri nella definizione della route e quelli utilizzati dal componente, prevenendo bug sottili che si manifesterebbero soltanto durante la navigazione verso una schermata specifica.
Schermate modali e opzioni di presentazione
Le modali in Expo Router sono schermate ordinarie configurate con presentation: 'modal' nel layout. Questo approccio rispetta la convenzione del routing file-based: una modale rimane semplicemente una route come le altre.
import { Stack } from 'expo-router'
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="index" />
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<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 = () => {
router.back()
}
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,
},
})Navigando verso /create-post, la presentazione modale viene attivata automaticamente. La chiamata a router.back() chiude la modale e riporta l'utente alla schermata precedente nello stack di navigazione.
Navigazione programmatica e API del router
Oltre al componente Link, Expo Router mette a disposizione un'API imperativa attraverso l'oggetto router. Questa consente di gestire la navigazione innescata dalla logica di business piuttosto che da un'interazione diretta dell'utente.
import { router } from 'expo-router'
router.push('/profile/settings')
router.replace('/login')
router.back()
router.push({
pathname: '/product/[id]',
params: { id: '42', source: 'recommendations' },
})
import { useRouter } from 'expo-router'
function BackButton() {
const router = useRouter()
return router.canGoBack() ? (
<Button title="Back" onPress={() => router.back()} />
) : null
}La distinzione tra router.push e router.replace risulta determinante nei flussi di autenticazione. Dopo un login riuscito, router.replace('/dashboard') impedisce all'utente di tornare alla schermata di login tramite il pulsante indietro, evitando un ciclo di navigazione indesiderato.
router.replace() sostituisce la voce corrente nella cronologia di navigazione. Per le guardie di autenticazione che reindirizzano gli utenti non autenticati, risulta preferibile utilizzare <Redirect href="/login" /> nel rendering del componente. Quest'ultimo si attiva durante la fase di rendering e funziona correttamente con il rendering lato server sul web.
Middleware e protezione delle route
Expo Router v6 introduce il middleware lato server per la logica applicata a livello di route. Il file +middleware.ts intercetta le richieste prima che raggiungano il componente della route, consentendo verifiche di autenticazione, redirect e manipolazione degli header HTTP.
import { type MiddlewareRequest } from 'expo-router/server'
export function middleware(request: MiddlewareRequest) {
const { pathname } = request.nextUrl
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
}Sulle piattaforme native, il middleware lato server non viene eseguito. La protezione delle route si basa quindi su guardie lato client. Il pattern piu diffuso consiste nell'avvolgere i layout protetti con una verifica di autenticazione:
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 />
}Questo pattern di layout protetto garantisce che nessuna schermata all'interno del gruppo venga renderizzata senza autenticazione preventiva. Il componente Redirect di Expo Router esegue il reindirizzamento prima che il contenuto protetto venga montato nell'albero dei componenti.
Il middleware lato server funziona esclusivamente sul web con il rendering lato server. Per le applicazioni native, risulta indispensabile implementare guardie lato client nei componenti di layout. Combinare entrambi gli approcci assicura una protezione coerente su tutte le piattaforme di destinazione.
Conclusione
Expo Router v6 porta nell'ecosistema React Native un approccio alla navigazione che allinea lo sviluppo mobile alle convenzioni consolidate dei framework web moderni. I punti fondamentali da ricordare:
- Expo Router v6 sostituisce la configurazione manuale della navigazione con convenzioni basate sui file, trasformando ogni file nella directory
appin una route automatica - I layout definiti tramite i file
_layout.tsxcreano gerarchie di navigazione -- stack, schede e drawer -- senza alcun file di configurazione centralizzato - Le route dinamiche con
[param].tsxe le route catch-all con[...slug].tsxgestiscono la navigazione parametrizzata con supporto TypeScript completo - La tipizzazione delle route rileva i link di navigazione non validi in fase di compilazione, quando la funzionalita viene attivata in
app.json - Le schermate modali, la navigazione programmatica tramite
router.push/replace/backe il middleware lato server completano il toolkit del routing - I gruppi di route tramite directory racchiuse tra parentesi organizzano il codice senza modificare gli URL, mantenendo un'alberatura leggibile anche con la crescita dell'applicazione
- Le guardie lato client nei layout gestiscono l'autenticazione sul nativo, mentre il middleware lato server copre il web -- la combinazione di entrambi garantisce una copertura multipiattaforma completa
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Tag
Condividi
