Skip to content

RN Lezione 9: Navigazione Stack con Expo Router

  • 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/account

Se il progetto è stato creato con create-expo-app, Expo Router è già incluso.

Altrimenti:

Terminal window
npx expo install expo-router

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>
);
}
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!


import { router } from 'expo-router';
// Vai avanti (aggiunge allo stack)
router.push('/dettaglio');
// Torna indietro
router.back();
// Sostituisci la schermata corrente (senza tornare indietro)
router.replace('/login');
// Vai alla home (svuota lo stack)
router.replace('/');

// Con oggetto params
<Button
title="Vedi dettaglio utente"
onPress={() => router.push({
pathname: '/dettaglio',
params: {
id: 42,
nome: 'Mario Rossi',
}
})}
/>
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'. Usa Number(params.id) se serve un numero.


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>
);
}
// 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 componente
export default function Dettaglio() {
const { nome } = useLocalSearchParams();
return (
<View>
{/* ... */}
</View>
);
}
presentation: 'card' // Default: scivola da destra
presentation: 'modal' // Scivola dal basso
presentation: 'transparentModal' // Modale trasparente

6. Esempio guidato: App profili con navigazione

Section titled “6. Esempio guidato: App profili con navigazione”
app/
├── _layout.js ← Configurazione stack
├── index.js ← Lista utenti
└── profilo.js ← Dettaglio utente
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>
);
}
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>
);
}
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>
);
}

app/
├── (tabs)/
│ ├── _layout.js
│ ├── index.js
│ ├── cerca.js
│ └── profilo.js
├── auth/
│ ├── login.js
│ └── register.js
└── _layout.js ← Layout RADICE (Stack globale)

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>

FunzioneCodice
Navigarouter.push('/path')
Naviga con parametrirouter.push({ pathname: '...', params: {...} })
Torna indietrorouter.back()
Sostituiscirouter.replace('/path')
Leggi parametriconst p = useLocalSearchParams()
Link dichiarativo<Link href="/path">...</Link>

Crea un’app con due schermate:

  1. Schermata Home (/):

    • Lista di film (FlatList con dati locali)
    • Ogni film: titolo, anno, genere, rating
    • Clicca → naviga al dettaglio
  2. Schermata Dettaglio (/film.js):

    • Mostra: titolo (grande), anno, genere, rating, descrizione
    • Pulsante ”← Torna ai film”
  3. 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...' },
];