Navegación Anidada y Parámetros entre Pantallas

Lectura
15 min~11 min lectura
Objetivo de la lección

Al final de esta lección, tendrás las herramientas para diseñar la estructura de navegación de aplicaciones del mundo real.

Puntos de control
  • Concepto Clave: Jerarquías de Navegación y Flujo de Datos
  • Cómo Funciona en la Práctica: Componiendo Navegadores
  • Código en Acción: App de Catálogo con Tabs y Stacks Anidados
  • Estructura de Navegadores Anidados
Lección: Navegación Anidada y Parámetros entre Pantallas

Navegación Anidada y Parámetros entre Pantallas

En esta lección, profundizaremos en dos pilares fundamentales para construir aplicaciones móviles complejas y bien estructuradas con React Native y Expo: la navegación anidada y la gestión avanzada de parámetros entre pantallas. Mientras que las lecciones iniciales te enseñaron a moverte entre pantallas simples, aquí aprenderás a organizar flujos de usuario intrincados, como aquellos que combinan tabs, stacks y drawers, y a pasar datos de manera eficiente y segura a través de tu aplicación. Dominar estos conceptos es lo que separa una app prototipo de una aplicación lista para producción, con una arquitectura de navegación clara, mantenible y con una excelente experiencia de usuario.

Exploraremos el ecosistema de React Navigation, la librería estándar de facto en React Native, enfocándonos en cómo componer distintos tipos de navegadores (navigators) y cómo diseñar la comunicación entre componentes de pantalla. Abordaremos desde la teoría detrás de la navegación anidada hasta patrones prácticos para pasar objetos complejos, manejar callbacks y evitar los errores más comunes que surgen en este ámbito. Al final de esta lección, tendrás las herramientas para diseñar la estructura de navegación de aplicaciones del mundo real.

Concepto Clave: Jerarquías de Navegación y Flujo de Datos

Imagina la estructura de navegación de tu aplicación como el plano de un gran centro comercial. El centro comercial en sí (tu app) tiene una entrada principal. Dentro, encuentras secciones claras: una zona de restaurantes, una de moda y un cine. Cada una de estas secciones es un navegador anidado (por ejemplo, un Tab Navigator). Ahora, al entrar a la sección de moda, descubres que está organizada en diferentes pasillos (cada uno podría ser un Stack Navigator): pasillo de ropa deportiva, pasillo de calzado, etc. Dentro del pasillo de calzado, puedes caminar hacia adelante y atrás entre las distintas tiendas (pantallas). Esta estructura jerárquica y anidada es la esencia de la navegación en apps complejas.

Por otro lado, los parámetros (o route params) son como los tickets o comprobantes que llevas de una tienda a otra. Si en la tienda de zapatos (Pantalla A) eliges un modelo específico, ese "ticket" con el ID o los detalles del zapato es lo que pasas a la pantalla de detalles (Pantalla B) para que esta sepa exactamente qué producto mostrar. La gestión de estos parámetros no es solo pasar un valor; se trata de definir contratos claros entre pantallas, validar la información recibida y manejar escenarios donde los datos puedan faltar, asegurando la robustez de tu aplicación.

Tip del Instructor: Un error de concepto frecuente es pensar que todos los estados de la app deben viajar como parámetros de navegación. Los parámetros son ideales para datos de identificación o contexto necesario para inicializar una pantalla. Para estados globales que muchas pantallas comparten (como el carrito de compras o el perfil del usuario logueado), se debe usar un sistema de gestión de estado global (como Context API, Zustand o Redux), que cubriremos en lecciones posteriores. Usa la herramienta correcta para cada trabajo.

Cómo Funciona en la Práctica: Componiendo Navegadores

En la práctica, la navegación anidada se implementa renderizando un componente navegador dentro de la pantalla de otro navegador. El patrón más común es tener un navegador principal (a menudo un Drawer o un Bottom Tab) cuyas pantallas sean, en realidad, otros navegadores. Por ejemplo, una pantalla llamada "HomeTab" en tu Tab Navigator no será un componente de pantalla común, sino una instancia de un Stack Navigator que contiene las pantallas "Feed", "Notifications" y "ProfileDetail". React Navigation maneja esta jerarquía de forma transparente, proporcionando el objeto de navigación y la ruta correctos a cada pantalla en su contexto.

El flujo para pasar parámetros implica dos operaciones fundamentales: navegar y obtener. Al realizar una navegación (mediante `navigation.navigate('RutaDestino', { params })`), se envía un objeto opcional de parámetros. En la pantalla destino, estos parámetros están disponibles en `route.params`. Es crucial realizar una verificación defensiva aquí, ya que `route.params` podría ser `undefined` si la pantalla se navegó sin parámetros. Un patrón seguro es usar desestructuración con valores por defecto: `const { itemId = 'defaultId', title = 'Sin título' } = route.params || {};`.

Un patrón avanzado pero extremadamente útil es pasar funciones callback como parámetros. Esto permite que una pantalla hija (por ejemplo, un formulario de edición) comunique un resultado directamente a su pantalla padre (por ejemplo, una lista). Sin embargo, debe hacerse con cuidado, evitando pasar funciones complejas que puedan causar problemas de rendimiento o ciclos de vida. Se suele preferir un patrón basado en eventos o en actualización de estado global para comunicaciones complejas ascendentes.

Código en Acción: App de Catálogo con Tabs y Stacks Anidados

Vamos a construir un ejemplo integral: una app de catálogo de productos. Tendrá un Bottom Tab Navigator con dos pestañas: "Inicio" y "Favoritos". La pestaña "Inicio" será, en realidad, un Stack Navigator anidado con dos pantallas: una lista de productos y un detalle de producto. La pestaña "Favoritos" será otro Stack Navigator independiente. Aprenderemos a pasar el objeto de un producto completo a la pantalla de detalle y a actualizar la lista desde el detalle.

Estructura de Navegadores Anidados

Primero, definimos nuestra estructura principal de navegación en `App.js` o un archivo similar.


// App.js
import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import HomeStack from './navigation/HomeStack';
import FavoritesStack from './navigation/FavoritesStack';
import { Ionicons } from '@expo/vector-icons';

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator
        screenOptions={({ route }) => ({
          tabBarIcon: ({ focused, color, size }) => {
            let iconName;
            if (route.name === 'Inicio') {
              iconName = focused ? 'home' : 'home-outline';
            } else if (route.name === 'Favoritos') {
              iconName = focused ? 'heart' : 'heart-outline';
            }
            return <Ionicons name={iconName} size={size} color={color} />;
          },
          tabBarActiveTintColor: 'tomato',
          tabBarInactiveTintColor: 'gray',
          headerShown: false, // Ocultamos el header del Tab Navigator porque lo manejarán los stacks anidados
        })}
      >
        <Tab.Screen name="Inicio" component={HomeStack} />
        <Tab.Screen name="Favoritos" component={FavoritesStack} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}
    

Stack Navigator Anidado y Paso de Parámetros

Ahora, creamos el `HomeStack.js`. Observa cómo el componente `HomeStack` es un Stack Navigator que se usa como componente de una pantalla del Tab Navigator.


// navigation/HomeStack.js
import React from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import ProductListScreen from '../screens/ProductListScreen';
import ProductDetailScreen from '../screens/ProductDetailScreen';

const Stack = createNativeStackNavigator();

const HomeStack = () => {
  return (
    <Stack.Navigator
      screenOptions={{
        headerStyle: { backgroundColor: '#f4511e' },
        headerTintColor: '#fff',
      }}
    >
      <Stack.Screen
        name="ProductList"
        component={ProductListScreen}
        options={{ title: 'Nuestros Productos' }}
      />
      <Stack.Screen
        name="ProductDetail"
        component={ProductDetailScreen}
        options={({ route }) => ({ title: route.params?.product?.name || 'Detalle' })}
      />
    </Stack.Navigator>
  );
};

export default HomeStack;
    

Pantallas que Navegan y Reciben Parámetros

Finalmente, implementamos las pantallas que consumen esta estructura. La lista navega al detalle pasando un objeto producto completo, y el detalle lo recibe y muestra.


// screens/ProductListScreen.js
import React from 'react';
import { View, FlatList, Text, TouchableOpacity, StyleSheet } from 'react-native';

const PRODUCTS = [
  { id: '1', name: 'Laptop Pro', price: 1299, description: 'Potente laptop para trabajo.' },
  { id: '2', name: 'Mouse Inalámbrico', price: 49, description: 'Mouse ergonómico inalámbrico.' },
  { id: '3', name: 'Teclado Mecánico', price: 89, description: 'Teclado mecánico con RGB.' },
];

const ProductListScreen = ({ navigation }) => {
  const renderItem = ({ item }) => (
    <TouchableOpacity
      style={styles.itemContainer}
      => navigation.navigate('ProductDetail', { product: item })}
    >
      <Text style={styles.itemName}>{item.name}</Text>
      <Text style={styles.itemPrice}>${item.price}</Text>
    </TouchableOpacity>
  );

  return (
    <View style={styles.container}>
      <FlatList
        data={PRODUCTS}
        renderItem={renderItem}
        keyExtractor={item => item.id}
        contentContainerStyle={styles.list}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, backgroundColor: '#f5f5f5' },
  list: { padding: 16 },
  itemContainer: {
    backgroundColor: 'white',
    padding: 20,
    marginBottom: 12,
    borderRadius: 8,
    elevation: 2,
  },
  itemName: { fontSize: 18, fontWeight: 'bold' },
  itemPrice: { fontSize: 16, color: 'green', marginTop: 4 },
});

export default ProductListScreen;

// screens/ProductDetailScreen.js
import React from 'react';
import { View, Text, StyleSheet, Button, Alert } from 'react-native';

const ProductDetailScreen = ({ route, navigation }) => {
  // Verificación defensiva CRUCIAL. route.params podría ser undefined.
  const { product } = route.params || {};

  if (!product) {
    return (
      <View style={styles.container}>
        <Text>Producto no encontrado.</Text>
        <Button title="Volver" => navigation.goBack()} />
      </View>
    );
  }

  const handleAddToFavorites = () => {
    // Aquí normalmente se enviaría a un estado global (Context/Redux).
    Alert.alert('Éxito', `"${product.name}" añadido a favoritos.`);
    // Ejemplo de cómo podríamos pasar información de vuelta a la pantalla anterior.
    // navigation.navigate('ProductList', { refreshed: true }); // Patrón alternativo
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>{product.name}</Text>
      <Text style={styles.price}>Precio: ${product.price}</Text>
      <Text style={styles.description}>{product.description}</Text>
      <View style={styles.buttonContainer}>
        <Button title="Añadir a Favoritos" />
        <Button title="Volver a la Lista" => navigation.goBack()} />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, padding: 20 },
  title: { fontSize: 28, fontWeight: 'bold', marginBottom: 10 },
  price: { fontSize: 22, color: 'green', marginBottom: 15 },
  description: { fontSize: 18, lineHeight: 26, marginBottom: 30 },
  buttonContainer: { gap: 10 },
});

export default ProductDetailScreen;
    

Errores Comunes y Cómo Evitarlos

Al trabajar con navegación anidada y parámetros, es fácil caer en ciertas trampas que pueden causar crashes o comportamientos inesperados en tu aplicación. Aquí te presentamos los más frecuentes y sus soluciones.

1. No verificar `route.params` antes de usarlo. Este es el error número uno. Si navegas a una pantalla directamente (por ejemplo, desde un deep link) o si olvidas pasar un parámetro, tu app intentará acceder a una propiedad de `undefined`. Solución: Siempre usa verificación condicional o desestructuración con valor por defecto, como se muestra en el código de `ProductDetailScreen`.

2. Anidar navegadores en un nivel incorrecto, causando headers dobles o comportamiento de gestos extraño. Un síntoma común es ver dos headers superpuestos. Solución: Recuerda configurar `headerShown: false` en el navegador padre (como el Tab Navigator) cuando sus pantallas hijas sean stacks que ya manejan su propio header. Planifica tu jerarquía visualmente antes de codificar.

3. Pasar objetos demasiado grandes o complejos como parámetros. Pasar un objeto con decenas de campos o funciones pesadas puede impactar el rendimiento y la serialización (especialmente importante si usas deep linking o persistencia de estado de navegación). Solución: Pasa solo el identificador único (ID) y deja que la pantalla destino recupere los datos completos de una fuente de verdad (como una API, Context o base de datos local).

4. Intentar navegar a una ruta que no existe en el navegador actual. Desde un componente dentro de un Stack Navigator anidado, no puedes navegar directamente a una pantalla que pertenezca a otro Tab de forma simple. Solución: Usa la navegación anidada correctamente. Para navegar entre tabs, puedes acceder al navigator padre usando `navigation.getParent()` o, mejor aún, usar un sistema de eventos o estado global para orquestar cambios de navegación complejos.

5. Olvidar que los parámetros no son reactivos. Si cambias los `route.params` en la pantalla origen después de haber navegado, la pantalla destino no se actualizará automáticamente. Los parámetros son una instantánea en el momento de la navegación. Solución: Para datos que deben estar sincronizados, utiliza un estado global o pasa callbacks (con las precauciones mencionadas) para notificar cambios.

Checklist de Dominio

Para verificar que has comprendido y puedes aplicar los conceptos de esta lección, asegúrate de poder realizar las siguientes tareas:

  • Crear una estructura de navegación que combine al menos dos tipos de navegadores (ej: Tabs anidando Stacks).
  • Navegar desde una pantalla dentro de un Stack anidado a otra pantalla del mismo Stack, pasando un objeto con múltiples propiedades como parámetro.
  • En la pantalla destino, recuperar los parámetros de forma segura usando desestructuración con valores por defecto y manejar el caso en que no existan.
  • Configurar opciones de pantalla (como el título del header) de forma dinámica basándose en los parámetros recibidos (`route.params`).
  • Navegar desde una pantalla hacia atrás en el historial (`goBack`) y hacia la pantalla inicial de un stack (`popToTop`).
  • Identificar cuándo es apropiado usar parámetros de navegación y cuándo es mejor usar un estado global.
  • Explicar el problema de los "headers dobles" en navegación anidada y saber cómo solucionarlo.
  • Implementar un flujo donde una pantalla de detalle pueda notificar un cambio a la pantalla de lista (por ejemplo, marcando un favorito) utilizando un método adecuado (callback vía params, estado global o actualización de parámetros al retroceder).
Falar no WhatsApp
Laboratorio de práctica

Antes de marcar esta lección como completa, escribí una evidencia breve para Desarrollo de Apps Nativas con React Native y Expo: De Cero a Producción: un ejemplo, una decisión, una captura, una mini demo o una nota que puedas reutilizar en portfolio.

Reflexión rápida

¿Qué cambiarías en tu forma de trabajar después de aplicar navegación anidada y parámetros entre pantallas?

De lección a portfolio

Convertí esta lección en una prueba técnica visible.

Una app pequeña publicada, con README y decisiones explicadas, funciona mejor que una lista de tecnologías sueltas.

Paso 1

Creá una demo mínima que use el concepto de la lección.

Paso 2

Escribí un README corto con objetivo, stack, decisión técnica y mejora futura.

Paso 3

Publicá la demo y enlazala desde tu perfil profesional.

Newsletter Cursalo

Recibí rutas y cursos nuevos

Sumate para recibir recursos orientados a empleo y portfolio.

  • Rutas de empleo
  • Cursos prácticos
  • Portfolio y entrevistas

Sin spam. También podés entrar con tu cuenta para guardar progreso. Iniciá sesión

Navegación Anidada y Parámetros entre Pantallas | Cursalo