Typescript
react native
expo
Expo Router
React Navigation
Desarrollo Móvil
Cuando comienzas a desarrollar con React Native, uno de los primeros retos que aparece es entender cómo funciona la navegación entre pantallas. En las apps móviles, moverse de una vista a otra no es un detalle menor: define la estructura completa de la experiencia del usuario.
A diferencia del desarrollo web, donde un enlace cambia de página y el navegador mantiene el historial, en una app móvil todo ocurre dentro de una única aplicación. Por eso, necesitamos una biblioteca de navegación que gestione ese historial internamente, controle las transiciones y permita pasar parámetros entre pantallas.
Expo Router forma parte de las versiones más recientes de Expo. Su filosofía es simple: la estructura de carpetas define tu navegación. Cada archivo dentro del directorio app/
se convierte automáticamente en una ruta o pantalla.
1app/ 2 ├─ index.tsx → Pantalla principal (/) 3 ├─ profile.tsx → Pantalla de perfil (/profile) 4 ├─ settings/ 5 │ └─ index.tsx → Pantalla de configuración (/settings) 6 └─ _layout.tsx → Layout común (navegación Stack o Tab)
No necesitas registrar manualmente cada pantalla ni definir rutas en un archivo central. Esto hace que el código sea más predecible, legible y fácil de escalar.
El patrón Stack (pila) es probablemente el más común. Imagina un conjunto de pantallas apiladas: cuando navegas a una nueva vista, se “empuja” encima de la anterior; al volver atrás, se “saca” de la pila.
1// app/_layout.tsx 2import { Stack } from "expo-router"; 3 4export default function Layout() { 5 return ( 6 <Stack> 7 <Stack.Screen name="index" options={{ title: "Inicio" }} /> 8 <Stack.Screen name="profile" options={{ title: "Perfil" }} /> 9 </Stack> 10 ); 11}
Cada archivo dentro de app/
se transforma en una pantalla del stack. Esto facilita el flujo jerárquico: por ejemplo, desde una lista hacia un detalle.
1// app/(tabs)/_layout.tsx 2import { Tabs } from "expo-router"; 3 4export default function Layout() { 5 return ( 6 <Tabs> 7 <Tabs.Screen name="home" options={{ title: "Inicio" }} /> 8 <Tabs.Screen name="settings" options={{ title: "Configuración" }} /> 9 </Tabs> 10 ); 11}
Estructura típica:
1app/ 2 └─ (tabs)/ 3 ├─ _layout.tsx 4 ├─ home.tsx 5 └─ settings.tsx
Cada pestaña es una pantalla independiente, pero todas comparten el mismo layout inferior.
Una de las necesidades más comunes es enviar información de una vista a otra. Por ejemplo, al hacer clic en un usuario, queremos abrir su perfil y mostrar sus datos.
Con Expo Router, esto se logra de forma declarativa:
1<Link href={{ pathname: "/profile", params: { userId: 42 } }}> 2 Ver perfil 3</Link>
1import { useLocalSearchParams } from "expo-router"; 2 3export default function ProfileScreen() { 4 const { userId } = useLocalSearchParams(); 5 return <Text>Perfil del usuario {userId}</Text>; 6}
No hay magia; los parámetros se leen con un hook, igual que harías con props o query params en React. Esta forma de comunicación mantiene la aplicación modular y fácil de depurar.
Una de las mayores ventajas de trabajar con Expo y React Native en TypeScript es la posibilidad de tipar tus rutas. Esto evita errores comunes como pasar parámetros incorrectos o escribir mal un nombre de pantalla.
Puedes definir un tipo global de rutas:
1export type RootStackParamList = { 2 index: undefined; 3 profile: { userId: number }; 4};
1<Link href={{ pathname: "/profile", params: { userId: 42 } }} />
Si intentas pasar un texto en lugar de un número, el compilador lo marcará como error. Para quienes vienen de lenguajes fuertemente tipados como Kotlin o Swift, esto resulta natural: el tipado fuerte aporta seguridad y confianza en el código.
Y si vienes del mundo nativo (Kotlin o Swift), notarás algo familiar, cada vista sigue siendo una unidad independiente, pero ahora con la flexibilidad de React y la potencia de JavaScript.