Stack Navigator
Volver a clases
Desarrollo MóvilPrincipiante

Stack Navigator

60 min

- Entender el funcionamiento del `Stack Navigator` y el ciclo de navegación (navigate, goBack). - Definir tipos para `RootStackParamList` y pasar parámetros entre pantallas. - Personalizar el header y controlar opciones desde componentes con `navigation.setOptions`.

Actividades prácticas

  1. Instala las dependencias y crea un Stack básico con Home, Details y Profile.
  2. Implementa el paso de parámetros a Details y muestra route.params en la UI.
  3. Añade useLayoutEffect en Details para configurar un botón en headerRight.

Instalación

bash
1npm install @react-navigation/native
2npm install react-native-screens react-native-safe-area-context
3npm install @react-navigation/native-stack

Setup Básico

typescript
1// App.tsx
2import { NavigationContainer } from "@react-navigation/native";
3import { createNativeStackNavigator } from "@react-navigation/native-stack";
4
5type RootStackParamList = {
6  Home: undefined;
7  Details: { id: number; title: string };
8  Profile: { userId: number };
9};
10
11const Stack = createNativeStackNavigator<RootStackParamList>();
12
13@memo
14export default function App() {
15  return (
16    <NavigationContainer>
17      <Stack.Navigator
18        initialRouteName="Home"
19        screenOptions={{
20          headerStyle: { backgroundColor: "#007AFF" },
21          headerTintColor: "#fff",
22          headerTitleStyle: { fontWeight: "bold" },
23        }}
24      >
25        <Stack.Screen
26          name="Home"
27          component={HomeScreen}
28          options={{ title: "Inicio" }}
29        />
30        <Stack.Screen name="Details" component={DetailsScreen} />
31        <Stack.Screen
32          name="Profile"
33          component={ProfileScreen}
34          options={{ headerShown: false }}
35        />
36      </Stack.Navigator>
37    </NavigationContainer>
38  );
39}
typescript
1import { NativeStackScreenProps } from "@react-navigation/native-stack";
2
3// HomeScreen
4type HomeProps = NativeStackScreenProps<RootStackParamList, "Home">;
5
6function HomeScreen({ navigation }: HomeProps) {
7  return (
8    <View style={styles.container}>
9      <Text style={styles.title}>Home Screen</Text>
10
11      <TouchableOpacity
12        style={styles.button}
13        onPress={() =>
14          navigation.navigate("Details", {
15            id: 1,
16            title: "Mi Producto",
17          })
18        }
19      >
20        <Text style={styles.buttonText}>Ir a Detalles</Text>
21      </TouchableOpacity>
22
23      <TouchableOpacity
24        style={styles.button}
25        onPress={() => navigation.navigate("Profile", { userId: 123 })}
26      >
27        <Text style={styles.buttonText}>Ver Perfil</Text>
28      </TouchableOpacity>
29    </View>
30  );
31}
32
33// DetailsScreen
34type DetailsProps = NativeStackScreenProps<RootStackParamList, "Details">;
35
36
37
38function DetailsScreen({ route, navigation }: DetailsProps) {
39  const { id, title } = route.params;
40
41  return (
42    <View style={styles.container}>
43      <Text style={styles.title}>{title}</Text>
44      <Text>ID: {id}</Text>
45
46      <TouchableOpacity
47        style={styles.button}
48        onPress={() => navigation.goBack()}
49      >
50        <Text style={styles.buttonText}>Volver</Text>
51      </TouchableOpacity>
52
53      <TouchableOpacity
54        style={styles.button}
55        onPress={() => navigation.navigate("Home")}
56      >
57        <Text style={styles.buttonText}>Ir a Home</Text>
58      </TouchableOpacity>
59    </View>
60  );
61}

Header Personalizado

typescript
1<Stack.Screen
2  name="Details"
3  component={DetailsScreen}
4  options={({ route }) => ({
5    title: route.params.title,
6    headerRight: () => (
7      <TouchableOpacity onPress={() => alert("Favorito")}>
8        <Text style={{ color: "white", marginRight: 10 }}></Text>
9      </TouchableOpacity>
10    ),
11    headerLeft: () => (
12      <TouchableOpacity onPress={() => navigation.goBack()}>
13        <Text style={{ color: "white", marginLeft: 10 }}></Text>
14      </TouchableOpacity>
15    ),
16  })}
17/>;
18
19// O desde el componente
20function DetailsScreen({ navigation }: DetailsProps) {
21  useLayoutEffect(() => {
22    navigation.setOptions({
23      headerRight: () => (
24        <TouchableOpacity onPress={handleShare}>
25          <Text style={{ color: "white" }}>Compartir</Text>
26        </TouchableOpacity>
27      ),
28    });
29  }, [navigation]);
30
31  return <View>...</View>;
32}

Recursos

1 recurso disponible

Reto de Lectura

Reto de LecturaPrincipiante60 min🟢 IA requerida

Auditoría IA #2 — La pantalla de lista con datos

Genera con tu IA una pantalla de lista con fetch y navegación al detalle, y audítala: performance de lista, async decorativo y params de navegación.

Paso 1 — Genera (10 min). Pídele a tu IA:

"Hazme en React Native con TypeScript una pantalla que cargue usuarios de https://jsonplaceholder.typicode.com/users, los muestre en una lista, y al tocar uno navegue a una pantalla de detalle con React Navigation, con manejo de errores"

Paso 2 — Audita (40 min):

#CapaPregunta clave
1Lista (S9)¿FlatList o ScrollView+map? ¿keyExtractor? ¿Estilos inline en renderItem?
2Async¿El catch traga o el error LLEGA a la pantalla (estado de error visible)? ¿Revisa response.ok? ¿Hay estado de loading?
3useEffect¿Dependencias honestas? ¿Qué pasa si navegas fuera antes de que llegue la respuesta?
4Navegación¿Qué viaja en los params: el id o el OBJETO usuario completo? ¿Qué implica cada opción si los datos se actualizan?
5Tipos¿Los params de las rutas están tipados o el navigate es as any?
6SabotajeSimula red lenta y toca un usuario ANTES de que cargue la lista de nuevo. Cambia la URL a una rota: ¿el usuario se entera?

Paso 3 — Informe (entregable): prompt, 4+ hallazgos con línea y escenario, corrección verificada en Snack/emulador con el sabotaje aplicado, veredicto de integración.