🧭 Navigation Guide (Expo Router)

Estructura de Navegación

app/
├── _layout.tsx              # Layout raíz (Stack principal)
├── (tabs)/                  # Grupo de tabs
│   ├── _layout.tsx          # Configuración de tabs
│   ├── (home)/              # Tab Home
│   │   ├── _layout.tsx      # Stack interno
│   │   ├── index.tsx        # Pantalla principal
│   │   └── item-detail.tsx  # Detalle de item
│   ├── explore/
│   ├── favorites/
│   └── profile/
└── notifications.tsx        # Modal (fuera de tabs)

Tipos de Navegación

1. Navegación con Tabs

// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';

export default function TabLayout() {
  return (
    <Tabs screenOptions={{ headerShown: false }}>
      <Tabs.Screen
        name="(home)"
        options={{
          title: 'Home',
          tabBarIcon: ({ color, size }) => <Home size={size} color={color} />,
        }}
      />
      <Tabs.Screen
        name="explore"
        options={{
          title: 'Explorar',
          tabBarIcon: ({ color, size }) => <Compass size={size} color={color} />,
        }}
      />
    </Tabs>
  );
}

2. Stack Interno en Tab

// app/(tabs)/(home)/_layout.tsx
import { Stack } from 'expo-router';

export default function HomeLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: 'Home' }} />
      <Stack.Screen 
        name="item-detail" 
        options={{ 
          title: 'Detalle',
          headerBackTitle: 'Volver',
        }} 
      />
    </Stack>
  );
}

3. Modales (Fuera de Tabs)

// app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      <Stack.Screen 
        name="notifications" 
        options={{ 
          presentation: 'modal',
          title: 'Notificaciones',
        }} 
      />
    </Stack>
  );
}

useRouter

import { useRouter } from 'expo-router';

function MyComponent() {
  const router = useRouter();

  // Navegar a una ruta
  router.push('/explore');

  // Con parámetros
  router.push({ 
    pathname: '/item-detail', 
    params: { id: '123' } 
  });

  // Reemplazar (sin poder volver)
  router.replace('/home');

  // Go back
  router.back();

  // Ir a tab específico
  router.push('/(tabs)/favorites');
}

Parámetros de Ruta

// En la pantalla de detalle
import { useLocalSearchParams } from 'expo-router';

function DetailScreen() {
  const { id, title } = useLocalSearchParams<{ 
    id: string; 
    title?: string; 
  }>();

  return <Text>Item ID: {id}</Text>;
}
import { Link } from 'expo-router';

<Link href="/explore" asChild>
  <TouchableOpacity>
    <Text>Ir a Explorar</Text>
  </TouchableOpacity>
</Link>

// Con parámetros
<Link 
  href={{ pathname: '/item-detail', params: { id: '123' } }} 
  asChild
>
  <Button title="Ver detalle" />
</Link>

Configuración de Pantallas

Opciones de Stack.Screen

<Stack.Screen
  name="screen"
  options={{
    // Título
    title: 'Mi Pantalla',
    
    // Header
    headerShown: true,
    headerStyle: { backgroundColor: Colors.primary },
    headerTintColor: Colors.textInverse,
    headerTitleStyle: { fontWeight: 'bold' },
    
    // Botones del header
    headerLeft: () => <BackButton />,
    headerRight: () => <SettingsButton />,
    
    // Presentación
    presentation: 'modal', // 'card' | 'modal' | 'transparentModal'
    animation: 'slide_from_right', // 'fade' | 'slide_from_bottom' | etc.
    
    // Gestos
    gestureEnabled: true,
    fullScreenGestureEnabled: true,
  }}
/>

Opciones Dinámicas

// Dentro del componente de la pantalla
import { Stack } from 'expo-router';

function ProductScreen() {
  const { name } = useProduct();

  return (
    <>
      <Stack.Screen 
        options={{ 
          title: name,
          headerRight: () => <ShareButton />,
        }} 
      />
      {/* Contenido */}
    </>
  );
}

Patrones Comunes

Deep Linking

// Navegar a pantalla anidada
router.push('/(tabs)/profile/edit-profile');

// Desde notificación push
const handleNotification = (notification) => {
  const { screen, params } = notification.data;
  router.push({ pathname: screen, params });
};

Proteger Rutas

// En _layout.tsx
function RootLayoutNav() {
  const { user, isLoading } = useAuth();

  if (isLoading) {
    return <SplashScreen />;
  }

  return (
    <Stack>
      {user ? (
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
      ) : (
        <Stack.Screen name="login" options={{ headerShown: false }} />
      )}
    </Stack>
  );
}

Resetear Navegación

// Resetear al inicio después de logout
import { useNavigation, CommonActions } from '@react-navigation/native';

const navigation = useNavigation();

navigation.dispatch(
  CommonActions.reset({
    index: 0,
    routes: [{ name: '(tabs)' }],
  })
);

Tips y Mejores Prácticas

  1. Usar grupos (parenthesis) para organizar sin afectar URLs
  2. Evitar navegación profunda - máximo 3-4 niveles
  3. Usar modales para flujos que no necesitan historial
  4. Precargar datos con React Query antes de navegar
  5. Manejar estado de carga al navegar entre pantallas