RN Lezione 9: Navigazione Stack con Expo Router
Obiettivi
Section titled “Obiettivi”- Capire il file-based routing di Expo Router
- Navigare tra schermate con
router.push() - Passare parametri tra schermate
- Gestire il pulsante back
1. Expo Router — routing basato su file system
Section titled “1. Expo Router — routing basato su file system”Expo Router usa la struttura delle cartelle per definire le route (come le pagine web).
app/├── index.js ← Schermata Home (route: /)├── dettaglio.js ← Schermata Dettaglio (route: /dettaglio)├── profilo.js ← Schermata Profilo (route: /profilo)└── settings/ ├── index.js ← Route: /settings └── account.js ← Route: /settings/accountSe il progetto è stato creato con create-expo-app, Expo Router è già incluso.
Altrimenti:
npx expo install expo-router2. Prima navigazione: Home → Dettaglio
Section titled “2. Prima navigazione: Home → Dettaglio”app/index.js — Schermata Home
Section titled “app/index.js — Schermata Home”import { View, Text, Button } from 'react-native';import { router } from 'expo-router';
export default function Home() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text style={{ fontSize: 24, marginBottom: 20 }}>🏠 Home</Text> <Button title="Vai al dettaglio" onPress={() => router.push('/dettaglio')} /> </View> );}app/dettaglio.js — Schermata Dettaglio
Section titled “app/dettaglio.js — Schermata Dettaglio”import { View, Text, Button } from 'react-native';import { router } from 'expo-router';
export default function Dettaglio() { return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text style={{ fontSize: 24, marginBottom: 20 }}>📋 Dettaglio</Text> <Button title="← Torna indietro" onPress={() => router.back()} /> </View> );}Nota: Su Android, il pulsante hardware “Back” funziona automaticamente!
3. Metodi di navigazione
Section titled “3. Metodi di navigazione”import { router } from 'expo-router';
// Vai avanti (aggiunge allo stack)router.push('/dettaglio');
// Torna indietrorouter.back();
// Sostituisci la schermata corrente (senza tornare indietro)router.replace('/login');
// Vai alla home (svuota lo stack)router.replace('/');4. Passare parametri tra schermate
Section titled “4. Passare parametri tra schermate”Da schermata A (index.js)
Section titled “Da schermata A (index.js)”// Con oggetto params<Button title="Vedi dettaglio utente" onPress={() => router.push({ pathname: '/dettaglio', params: { id: 42, nome: 'Mario Rossi', } })}/>In schermata B (dettaglio.js)
Section titled “In schermata B (dettaglio.js)”import { useLocalSearchParams } from 'expo-router';
export default function Dettaglio() { const params = useLocalSearchParams(); // params = { id: '42', nome: 'Mario Rossi' }
return ( <View> <Text>ID: {params.id}</Text> <Text>Nome: {params.nome}</Text> </View> );}Nota: i parametri sono stringhe! Se passi
id: 42, ricevi'42'. UsaNumber(params.id)se serve un numero.
5. Stack navigator con layout custom
Section titled “5. Stack navigator con layout custom”Crea app/_layout.js per configurare lo stack:
import { Stack } from 'expo-router';
export default function RootLayout() { return ( <Stack screenOptions={{ headerStyle: { backgroundColor: '#3498db' }, headerTintColor: 'white', headerTitleStyle: { fontWeight: 'bold' }, headerShown: true, }} > <Stack.Screen name="index" options={{ title: 'Home', headerShown: false, // Nasconde header su Home }} /> <Stack.Screen name="dettaglio" options={{ title: 'Dettaglio', }} /> <Stack.Screen name="profilo" options={{ title: 'Profilo utente', }} /> </Stack> );}Opzioni header
Section titled “Opzioni header”// Per schermata specifica (in _layout.js)<Stack.Screen name="settings" options={{ title: 'Impostazioni', headerStyle: { backgroundColor: '#2ecc71' }, headerTintColor: '#fff', headerBackTitle: 'Indietro', // iOS presentation: 'modal', // ← apre come modale }}/>
// Oppure dinamicamente nel componenteexport default function Dettaglio() { const { nome } = useLocalSearchParams();
return ( <View> {/* ... */} </View> );}presentation (tipi di transizione)
Section titled “presentation (tipi di transizione)”presentation: 'card' // Default: scivola da destrapresentation: 'modal' // Scivola dal bassopresentation: 'transparentModal' // Modale trasparente6. Esempio guidato: App profili con navigazione
Section titled “6. Esempio guidato: App profili con navigazione”Struttura
Section titled “Struttura”app/├── _layout.js ← Configurazione stack├── index.js ← Lista utenti└── profilo.js ← Dettaglio utenteapp/_layout.js
Section titled “app/_layout.js”import { Stack } from 'expo-router';
export default function Layout() { return ( <Stack> <Stack.Screen name="index" options={{ title: 'Utenti' }} /> <Stack.Screen name="profilo" options={{ title: 'Profilo' }} /> </Stack> );}app/index.js
Section titled “app/index.js”import { View, Text, FlatList, TouchableOpacity, StyleSheet } from 'react-native';import { router } from 'expo-router';
const UTENTI = [ { id: 1, nome: 'Mario', eta: 17, classe: '4A' }, { id: 2, nome: 'Sofia', eta: 16, classe: '4B' }, { id: 3, nome: 'Luca', eta: 17, classe: '4A' }, { id: 4, nome: 'Anna', eta: 16, classe: '4B' },];
export default function Home() { const renderItem = ({ item }) => ( <TouchableOpacity style={styles.card} onPress={() => router.push({ pathname: '/profilo', params: { id: item.id, nome: item.nome, eta: item.eta, classe: item.classe } })} > <View style={styles.avatar}> <Text style={styles.iniziale}>{item.nome[0]}</Text> </View> <View> <Text style={styles.nome}>{item.nome}</Text> <Text style={styles.classe}>{item.classe}</Text> </View> </TouchableOpacity> );
return ( <View style={styles.container}> <FlatList data={UTENTI} renderItem={renderItem} keyExtractor={item => item.id.toString()} /> </View> );}app/profilo.js
Section titled “app/profilo.js”import { View, Text, Button, StyleSheet } from 'react-native';import { useLocalSearchParams, router } from 'expo-router';
export default function Profilo() { const { id, nome, eta, classe } = useLocalSearchParams();
return ( <View style={styles.container}> <View style={styles.avatar}> <Text style={styles.iniziale}>{nome[0]}</Text> </View> <Text style={styles.nome}>{nome}</Text> <View style={styles.info}> <Text style={styles.label}>Classe: <Text style={styles.valore}>{classe}</Text></Text> <Text style={styles.label}>Età: <Text style={styles.valore}>{eta} anni</Text></Text> </View> <Button title="← Torna indietro" onPress={() => router.back()} /> </View> );}7. Navigazione annidata (nested routes)
Section titled “7. Navigazione annidata (nested routes)”app/├── (tabs)/│ ├── _layout.js│ ├── index.js│ ├── cerca.js│ └── profilo.js├── auth/│ ├── login.js│ └── register.js└── _layout.js ← Layout RADICE (Stack globale)8. Link — navigazione dichiarativa
Section titled “8. Link — navigazione dichiarativa”Come <a> in HTML:
import { Link } from 'expo-router';
<Link href="/dettaglio" style={styles.link}> Vai al dettaglio</Link>
<Link href={{ pathname: '/dettaglio', params: { id: 5, nome: 'Mario' } }} style={styles.link}> Vedi Mario</Link>9. Tabella riassuntiva Expo Router
Section titled “9. Tabella riassuntiva Expo Router”| Funzione | Codice |
|---|---|
| Naviga | router.push('/path') |
| Naviga con parametri | router.push({ pathname: '...', params: {...} }) |
| Torna indietro | router.back() |
| Sostituisci | router.replace('/path') |
| Leggi parametri | const p = useLocalSearchParams() |
| Link dichiarativo | <Link href="/path">...</Link> |
10. Esercizio autonomo
Section titled “10. Esercizio autonomo”🎯 Esercizio: “Catalogo Film”
Section titled “🎯 Esercizio: “Catalogo Film””Crea un’app con due schermate:
-
Schermata Home (
/):- Lista di film (FlatList con dati locali)
- Ogni film: titolo, anno, genere, rating
- Clicca → naviga al dettaglio
-
Schermata Dettaglio (
/film.js):- Mostra: titolo (grande), anno, genere, rating, descrizione
- Pulsante ”← Torna ai film”
-
Layout: stack con header colorato
const FILM = [ { id: 1, titolo: 'Inception', anno: 2010, genere: 'Fantascienza', rating: 8.8, descrizione: 'Un ladro specializzato...' }, { id: 2, titolo: 'Il Padrino', anno: 1972, genere: 'Dramma', rating: 9.2, descrizione: 'La saga della famiglia...' }, { id: 3, titolo: 'Interstellar', anno: 2014, genere: 'Fantascienza', rating: 8.7, descrizione: 'Un viaggio oltre...' },];