Navegación Avanzada en React Native: React Navigation v6
Este tutorial te guiará a través de React Navigation v6, la solución estándar para gestionar la navegación en aplicaciones React Native. Aprenderás a configurar diferentes tipos de navegadores, pasar parámetros entre pantallas y manejar flujos de autenticación para construir una experiencia de usuario robusta y coherente.
React Native permite a los desarrolladores crear aplicaciones móviles nativas usando JavaScript y React. Una parte fundamental de cualquier aplicación móvil es la navegación, que permite a los usuarios moverse entre diferentes pantallas y secciones de la aplicación. Para esto, la comunidad de React Native ha adoptado React Navigation como la solución estándar y más potente.
En este tutorial, exploraremos React Navigation en su versión 6, la más reciente y mejorada. Cubriremos desde los conceptos básicos hasta técnicas avanzadas para construir flujos de navegación complejos, incluyendo autenticación y anidamiento de navegadores.
🚀 ¿Qué es React Navigation?
React Navigation es una librería extensible y personalizable para la navegación en React Native. Proporciona una forma sencilla de construir una jerarquía de pantallas dentro de tu aplicación y manejar las transiciones entre ellas. A diferencia de las soluciones nativas, React Navigation utiliza JavaScript para definir y gestionar la navegación, lo que lo hace muy flexible y fácil de integrar con el estado de tu aplicación.
Ventajas de React Navigation v6 ✨
- Rendimiento optimizado: Mayor fluidez en las transiciones.
- API simplificada: Más fácil de usar y comprender.
- Flexibilidad: Permite anidar diferentes tipos de navegadores.
- Personalización: Amplias opciones para estilos y comportamientos.
- Comunidad activa: Gran soporte y documentación.
🛠️ Configuración Inicial
Antes de sumergirnos en la construcción de navegadores, necesitamos instalar React Navigation y sus dependencias.
Paso 1: Crear un proyecto React Native (si no tienes uno)
Si aún no tienes un proyecto, puedes crear uno con Expo CLI (recomendado para empezar) o React Native CLI:
npx create-expo-app MyNavigationApp
cd MyNavigationApp
O si prefieres React Native CLI:
npx react-native init MyNavigationApp --template react-native-template-typescript
cd MyNavigationApp
Paso 2: Instalar React Navigation y sus dependencias
Necesitamos instalar el paquete principal @react-navigation/native y sus dependencias de la expo-modules-core (si usas Expo) o react-native-screens y react-native-safe-area-context (para CLI).
Para Expo:
yarn add @react-navigation/native
npx expo install react-native-screens react-native-safe-area-context
Para React Native CLI:
yarn add @react-navigation/native
yarn add react-native-screens react-native-safe-area-context
cd ios && pod install && cd .. # Solo para iOS
Paso 3: Instalar un tipo de navegador (Stack Navigator)
El tipo de navegador más común y el que usaremos para empezar es el Stack Navigator, que proporciona la experiencia de navegación de 'pila' donde las pantallas se empujan una encima de otra.
yarn add @react-navigation/stack
Paso 4: Envolver la aplicación con NavigationContainer
Todas las aplicaciones que usan React Navigation deben estar envueltas en un NavigationContainer. Este componente gestiona el árbol de navegación y contiene el estado de navegación.
Modifica tu App.js (o App.tsx):
// App.js
import 'react-native-gesture-handler'; // Asegúrate de que esta línea esté al inicio si usas React Native CLI
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { View, Text, Button } from 'react-native';
// Componentes de pantalla de ejemplo
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>¡Bienvenido a Casa!</Text>
<Button
title="Ir a Detalles"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Pantalla de Detalles</Text>
<Button
title="Volver a Casa"
onPress={() => navigation.goBack()}
/>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Mi Inicio' }} />
<Stack.Screen name="Details" component={DetailsScreen} options={{ title: 'Más Detalles' }} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
📂 Tipos de Navegadores Comunes
React Navigation ofrece varios tipos de navegadores para diferentes patrones de interfaz de usuario. Los más comunes son:
1. Stack Navigator (Pila) 📚
El Stack Navigator es ideal para navegar entre pantallas de forma secuencial, como si estuvieras apilando cartas. Cada vez que navegas a una nueva pantalla, se empuja en la pila, y al retroceder, se saca la pantalla superior.
Uso:
import { createStackNavigator } from '@react-navigation/stack';
const Stack = createStackNavigator();
function MyStack() {
return (
<Stack.Navigator>
<Stack.Screen name="First" component={FirstScreen} />
<Stack.Screen name="Second" component={SecondScreen} />
</Stack.Navigator>
);
}
Opciones Comunes para Stack Navigator
Puedes personalizar el Stack Navigator y sus pantallas con el prop options en Stack.Screen o screenOptions en Stack.Navigator.
| Opción | Descripción | Ejemplo |
|---|---|---|
title | Título de la cabecera de la pantalla. | 'Mi Pantalla' |
headerStyle | Estilos para el contenedor de la cabecera. | { backgroundColor: '#f4511e' } |
headerTintColor | Color del texto y los iconos de la cabecera. | '#fff' |
headerTitleStyle | Estilos para el texto del título. | { fontWeight: 'bold' } |
headerBackTitle | Título del botón de retroceso en iOS. | 'Atrás' |
gestureEnabled | Habilita/deshabilita el gesto de deslizamiento para retroceder. | false |
2. Tab Navigator (Pestañas) 📑
El Tab Navigator (comúnmente Bottom Tab Navigator) es perfecto para la navegación de nivel superior, donde el usuario puede cambiar entre secciones principales de la aplicación con un solo toque. Las pestañas suelen estar en la parte inferior de la pantalla.
Instalación:
yarn add @react-navigation/bottom-tabs
Uso:
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import Ionicons from 'react-native-vector-icons/Ionicons'; // Ejemplo para iconos
// Pantallas de ejemplo
function FeedScreen() { /* ... */ }
function SettingsScreen() { /* ... */ }
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Feed') {
iconName = focused ? 'ios-information-circle' : 'ios-information-circle-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-list-box' : 'ios-list';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'tomato',
tabBarInactiveTintColor: 'gray',
})}
>
<Tab.Screen name="Feed" component={FeedScreen} options={{ title: 'Noticias' }} />
<Tab.Screen name="Settings" component={SettingsScreen} options={{ title: 'Ajustes' }} />
</Tab.Navigator>
);
}
3. Drawer Navigator (Lateral) ☰
El Drawer Navigator (cajón lateral) es útil para aplicaciones con muchas secciones o para navegación secundaria. Se abre deslizando desde el borde de la pantalla o tocando un icono de menú.
Instalación:
yarn add @react-navigation/drawer
Uso:
import { createDrawerNavigator } from '@react-navigation/drawer';
// Pantallas de ejemplo
function ArticleScreen() { /* ... */ }
function ProfileScreen() { /* ... */ }
const Drawer = createDrawerNavigator();
function MyDrawer() {
return (
<Drawer.Navigator initialRouteName="Articles">
<Drawer.Screen name="Articles" component={ArticleScreen} />
<Drawer.Screen name="Profile" component={ProfileScreen} />
</Drawer.Navigator>
);
}
🧩 Anidando Navegadores
Uno de los puntos fuertes de React Navigation es la capacidad de anidar navegadores. Esto significa que puedes tener, por ejemplo, un Stack Navigator dentro de una de las pestañas de un Tab Navigator. Esto es crucial para construir interfaces complejas y coherentes.
Ejemplo: Un Tab Navigator con Stack Navigators en cada pestaña.
Imagina que tienes una aplicación con pestañas de 'Inicio' y 'Perfil'. Dentro de 'Inicio', quieres tener una pila de navegación (Inicio -> Detalles del producto). Dentro de 'Perfil', también quieres una pila (Perfil -> Editar perfil).
// Stack para la pestaña de Inicio
const HomeStack = createStackNavigator();
function HomeStackScreen() {
return (
<HomeStack.Navigator>
<HomeStack.Screen name="Home" component={HomeScreen} options={{ title: 'Inicio App' }} />
<HomeStack.Screen name="ProductDetails" component={ProductDetailsScreen} options={{ title: 'Detalles' }} />
</HomeStack.Navigator>
);
}
// Stack para la pestaña de Perfil
const ProfileStack = createStackNavigator();
function ProfileStackScreen() {
return (
<ProfileStack.Navigator>
<ProfileStack.Screen name="Profile" component={ProfileScreen} options={{ title: 'Mi Perfil' }} />
<ProfileStack.Screen name="EditProfile" component={EditProfileScreen} options={{ title: 'Editar' }} />
</ProfileStack.Navigator>
);
}
// El Tab Navigator principal
const Tab = createBottomTabNavigator();
function AppTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="HomeTab" component={HomeStackScreen} options={{ headerShown: false, title: 'Inicio' }} />
<Tab.Screen name="ProfileTab" component={ProfileStackScreen} options={{ headerShown: false, title: 'Perfil' }} />
</Tab.Navigator>
);
}
// Y finalmente, el NavigationContainer principal
function App() {
return (
<NavigationContainer>
<AppTabs />
</NavigationContainer>
);
}
export default App;
🔗 Pasando Parámetros Entre Pantallas
Es muy común necesitar pasar datos de una pantalla a otra. React Navigation facilita esto a través del objeto params.
Envío de parámetros
Cuando navegas a una pantalla, puedes pasar un segundo argumento con un objeto de parámetros:
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Inicio</Text>
<Button
title="Ir a Detalles de Usuario (ID: 123)"
onPress={() => navigation.navigate('UserDetails', { userId: 123, userName: 'Alice' })}
/>
</View>
);
}
Recepción de parámetros
En la pantalla de destino, los parámetros están disponibles a través de route.params en el objeto route que se pasa como prop a los componentes de la pantalla:
function UserDetailsScreen({ route, navigation }) {
const { userId, userName } = route.params;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Detalles del Usuario</Text>
<Text>ID: {userId}</Text>
<Text>Nombre: {userName}</Text>
<Button title="Volver" onPress={() => navigation.goBack()} />
</View>
);
}
// Asegúrate de añadir esta pantalla al Stack Navigator
// <Stack.Screen name="UserDetails" component={UserDetailsScreen} />
🔐 Flujo de Autenticación
Un patrón muy común en aplicaciones móviles es un flujo de autenticación, donde los usuarios navegan entre pantallas de Login, Registro, Recuperar Contraseña antes de acceder a la parte principal de la aplicación. Una vez autenticados, se les muestra la interfaz de usuario de la aplicación. React Navigation maneja esto elegantemente con navegadores anidados condicionalmente.
El enfoque es tener un Stack Navigator principal que muestre:
- Un
Stack Navigatorde autenticación (Login, Registro, etc.) si el usuario no está autenticado. - Un
Tab Navigator(oDrawer Navigator) de la aplicación principal si el usuario está autenticado.
Estructura de código para autenticación
Primero, definamos las pantallas de autenticación y la aplicación principal.
// AuthStack.js
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { View, Text, Button } from 'react-native';
const AuthStack = createStackNavigator();
function SignInScreen({ navigation, signIn }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Pantalla de Inicio de Sesión</Text>
<Button title="Iniciar Sesión" onPress={() => signIn()} />
<Button title="Registrarse" onPress={() => navigation.navigate('SignUp')} />
</View>
);
}
function SignUpScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Pantalla de Registro</Text>
<Button title="Volver a Iniciar Sesión" onPress={() => navigation.goBack()} />
</View>
);
}
export function AuthStackNavigator({ signIn }) {
return (
<AuthStack.Navigator>
<AuthStack.Screen name="SignIn">
{props => <SignInScreen {...props} signIn={signIn} />}
</AuthStack.Screen>
<AuthStack.Screen name="SignUp" component={SignUpScreen} />
</AuthStack.Navigator>
);
}
// AppStack.js (Navegador principal de la aplicación autenticada)
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';
import { View, Text, Button } from 'react-native';
import Ionicons from 'react-native-vector-icons/Ionicons';
// Pantallas de ejemplo para la aplicación principal
function DashboardScreen({ signOut }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Panel de Control</Text>
<Button title="Cerrar Sesión" onPress={() => signOut()} />
</View>
);
}
function SettingsAppScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Ajustes de la App</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
export function AppTabNavigator({ signOut }) {
return (
<Tab.Navigator
screenOptions={({ route }) => ({
tabBarIcon: ({ focused, color, size }) => {
let iconName;
if (route.name === 'Dashboard') {
iconName = focused ? 'ios-speedometer' : 'ios-speedometer-outline';
} else if (route.name === 'Settings') {
iconName = focused ? 'ios-settings' : 'ios-settings-outline';
}
return <Ionicons name={iconName} size={size} color={color} />;
},
tabBarActiveTintColor: 'blue',
tabBarInactiveTintColor: 'gray',
headerShown: false // Oculta la cabecera del Tab Navigator si ya hay una externa o si no quieres una
})}
>
<Tab.Screen name="Dashboard">
{props => <DashboardScreen {...props} signOut={signOut} />}
</Tab.Screen>
<Tab.Screen name="Settings" component={SettingsAppScreen} />
</Tab.Navigator>
);
}
// App.js (Contenedor principal con lógica de autenticación)
import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { AuthStackNavigator } from './AuthStack'; // Asume que creaste estos archivos
import { AppTabNavigator } from './AppStack';
import { ActivityIndicator, View, AsyncStorage } from 'react-native'; // Usar SecureStore en producción
const AuthContext = React.createContext();
function App() {
const [state, dispatch] = React.useReducer(
(prevState, action) => {
switch (action.type) {
case 'RESTORE_TOKEN':
return {
...prevState,
userToken: action.token,
isLoading: false,
};
case 'SIGN_IN':
return {
...prevState,
isSignout: false,
userToken: action.token,
};
case 'SIGN_OUT':
return {
...prevState,
isSignout: true,
userToken: null,
};
}
},
{
isLoading: true,
isSignout: false,
userToken: null,
}
);
React.useEffect(() => {
// Recuperar el token del almacenamiento al iniciar la app
const bootstrapAsync = async () => {
let userToken;
try {
// En una app real, usarías SecureStore para tokens sensibles
userToken = await AsyncStorage.getItem('userToken');
} catch (e) {
// Restaurar token falló
}
dispatch({ type: 'RESTORE_TOKEN', token: userToken });
};
bootstrapAsync();
}, []);
const authContext = React.useMemo(
() => ({
signIn: async (data) => {
// Aquí deberías realizar una llamada a la API para autenticar
// Por simplicidad, simulamos un token
const userToken = 'dummy-auth-token';
await AsyncStorage.setItem('userToken', userToken);
dispatch({ type: 'SIGN_IN', token: userToken });
},
signOut: async () => {
await AsyncStorage.removeItem('userToken');
dispatch({ type: 'SIGN_OUT' });
},
signUp: async (data) => {
// Aquí harías una llamada a la API para registrar al usuario
// Y luego lo iniciarías sesión
const userToken = 'dummy-auth-token-new-user';
await AsyncStorage.setItem('userToken', userToken);
dispatch({ type: 'SIGN_IN', token: userToken });
},
}),
[]
);
if (state.isLoading) {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<AuthContext.Provider value={authContext}>
<NavigationContainer>
{state.userToken == null ? (
<AuthStackNavigator signIn={authContext.signIn} />
) : (
<AppTabNavigator signOut={authContext.signOut} />
)}
</NavigationContainer>
</AuthContext.Provider>
);
}
export default App;
En este patrón, el NavigationContainer decide qué conjunto de navegadores renderizar basándose en el estado de autenticación (userToken). Cuando userToken es null, se muestra el AuthStackNavigator. Cuando hay un userToken, se muestra el AppTabNavigator.
🎨 Personalización de Navegadores
React Navigation es altamente personalizable. Puedes ajustar casi todos los aspectos de la apariencia y el comportamiento.
Opciones de cabecera (Stack Navigator)
Las cabeceras son una parte clave de la interfaz. Puedes personalizar su estilo, los botones, los títulos y más.
<Stack.Screen
name="HomeScreen"
component={HomeScreen}
options={{
title: 'Mi Gran App',
headerStyle: {
backgroundColor: '#6200EE', // Color de fondo
},
headerTintColor: '#fff', // Color del texto y los iconos
headerTitleStyle: {
fontWeight: 'bold',
},
headerRight: () => (
<Button
onPress={() => alert('¡Presionaste el botón!')}
title="Info"
color="#fff"
/>
),
headerLeft: () => (
<Button
onPress={() => alert('¡Menú!')}
title="Menú"
color="#fff"
/>
)
}}
/>
Custom Drawer Content
Para el Drawer Navigator, puedes ir más allá de la lista de enlaces por defecto y crear tu propio componente para el contenido del cajón.
import {
DrawerContentScrollView,
DrawerItemList,
DrawerItem,
} from '@react-navigation/drawer';
import { Text, View, StyleSheet, Image } from 'react-native';
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<View style={styles.drawerHeader}>
<Image
source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
style={styles.drawerImage}
/>
<Text style={styles.drawerHeaderText}>Mi Perfil de Usuario</Text>
</View>
<DrawerItemList {...props} />
<DrawerItem
label="Ayuda"
onPress={() => alert('¡Necesitas ayuda!')}
icon={({ color, size }) => (
<Ionicons name="help-circle-outline" size={size} color={color} />
)}
/>
</DrawerContentScrollView>
);
}
// Luego, en tu Drawer Navigator:
// <Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
const styles = StyleSheet.create({
drawerHeader: {
padding: 20,
backgroundColor: '#f0f0f0',
alignItems: 'center',
justifyContent: 'center',
},
drawerImage: {
width: 80,
height: 80,
borderRadius: 40,
marginBottom: 10,
},
drawerHeaderText: {
fontSize: 18,
fontWeight: 'bold',
},
});
⏭️ Consideraciones Avanzadas
Deep Linking
React Navigation tiene un soporte robusto para Deep Linking, permitiendo que los usuarios abran tu aplicación directamente en una pantalla específica a través de un enlace web o un enlace universal. Esto es crucial para la experiencia de usuario y el marketing.
La configuración implica definir un linking prop en tu NavigationContainer.
const linking = {
prefixes: ['mychatapp://', 'https://mychatapp.com'],
config: {
screens: {
HomeTab: {
screens: {
Feed: 'feed',
ProductDetails: 'product/:id',
},
},
ProfileTab: 'profile',
},
},
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Cargando...</Text>}>
{/* ... tus navegadores ... */}
</NavigationContainer>
);
}
Tematización (Theming)
Puedes aplicar temas globales a tu aplicación para asegurarte de que los colores y estilos de navegación coincidan con el resto de tu interfaz.
import { NavigationContainer, DefaultTheme, DarkTheme } from '@react-navigation/native';
import { useColorScheme } from 'react-native';
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: 'rgb(255, 45, 85)',
background: 'rgb(242, 242, 242)',
card: 'rgb(255, 255, 255)',
text: 'rgb(28, 28, 30)',
border: 'rgb(199, 199, 204)',
notification: 'rgb(255, 69, 58)',
},
};
function App() {
const scheme = useColorScheme(); // 'light' o 'dark'
return (
<NavigationContainer theme={scheme === 'dark' ? DarkTheme : MyTheme}>
{/* ... */}
</NavigationContainer>
);
}
✅ Buenas Prácticas y Consejos
- Organiza tu código: Separa los navegadores en archivos (
AuthStack.js,AppTabs.js, etc.) para mantener la claridad. - Usa
useNavigationyuseRoutehooks: En lugar de pasarnavigationyroutecomo props, puedes usar estos hooks dentro de tus componentes para acceder a ellos.
import { useNavigation, useRoute } from '@react-navigation/native';
// ...
const navigation = useNavigation();
const route = useRoute();
const { userId } = route.params;
- Evita pasar props excesivamente: Si una pantalla necesita muchos datos, considera usar un sistema de gestión de estado global (Redux, Context API, Zustand, etc.).
- Optimiza el rendimiento: Ten en cuenta que cada pantalla es un componente de React. Evita renderizados innecesarios.
- Prueba a fondo: Asegúrate de que todos los flujos de navegación funcionen como se espera, especialmente los de autenticación y los casos extremos.
Ejemplo de tipificación con TypeScript
// types.ts
export type RootStackParamList = {
Home: undefined; // No toma parámetros
Details: { itemId: number; otherParam?: string }; // itemId es requerido, otherParam es opcional
UserDetails: { userId: number; userName: string };
SignIn: undefined;
SignUp: undefined;
Dashboard: undefined;
Settings: undefined;
// Para anidar stacks, define los sub-stacks aquí también
HomeStack: undefined;
ProfileStack: undefined;
Feed: undefined;
ProductDetails: { id: string };
Profile: undefined;
EditProfile: undefined;
};
// Y en tus componentes:
import { StackScreenProps } from '@react-navigation/stack';
import { CompositeScreenProps } from '@react-navigation/native';
import { BottomTabScreenProps } from '@react-navigation/bottom-tabs';
type HomeScreenProps = StackScreenProps<RootStackParamList, 'Home'>;
function HomeScreen({ navigation }: HomeScreenProps) { /* ... */ }
// Para una pantalla en un tab que está dentro de un stack:
type ProductDetailsScreenProps = CompositeScreenProps<
StackScreenProps<RootStackParamList, 'ProductDetails'>,
BottomTabScreenProps<RootStackParamList, 'HomeStack'> // Aquí HomeStack no toma parámetros, pero lo enlaza
>;
function ProductDetailsScreen({ route }: ProductDetailsScreenProps) {
const { id } = route.params;
// ...
}
Conclusión
Dominar React Navigation es un pilar fundamental para construir aplicaciones React Native de alta calidad. Hemos cubierto la configuración inicial, los tipos de navegadores más comunes (Stack, Tab, Drawer), cómo anidarlos para crear arquitecturas complejas, el manejo de parámetros y la implementación de un flujo de autenticación robusto. Con estas herramientas, estás bien equipado para diseñar y desarrollar experiencias de usuario fluidas y profesionales en tus proyectos móviles.
Sigue experimentando con las opciones de personalización y explora la documentación oficial para descubrir aún más posibilidades. ¡Feliz navegación!
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!