// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
export default function TabsLayout() {
return (
<Tabs screenOptions={{ tabBarActiveTintColor: '#007AFF' }}>
<Tabs.Screen
name="home"
options={{
title: 'Acasă',
headerShown: false, // Ascundem header-ul tab-ului pentru a nu se suprapune cu cel din Stack-ul intern
tabBarIcon: ({ color }) => <Ionicons name="home" size={24} color={color} />,
}}
/>
<Tabs.Screen
name="profile"
options={{
title: 'Profil',
tabBarIcon: ({ color }) => <Ionicons name="person" size={24} color={color} />,
}}
/>
</Tabs>
);
}Am migrat acum șase luni o aplicație de livrări cu peste 15.000 de utilizatori activi de la React Navigation clasic la Expo Router. Dacă te bate gândul să faci trecerea asta doar pentru că e la modă, oprește-te puțin. Hai să îți spun unde merită efortul și cum configurezi corect structura aia clasică de Tabs cu Stack-uri imbricate fără să-ți prinzi urechile în fișiere _layout.
Când merită să migrezi și când e doar bătaie de cap
Să fim sinceri: React Navigation e tăticul navigării în React Native. E stabil, îl știm de ani de zile și face exact ce îi ceri. Totuși, când proiectul crește, fișierul ăla imens în care declari toate rutele devine un coșmar de întreținut.
Aici strălucește Expo Router. Fiind bazat pe structura de directoare (file-system routing, exact ca în Next.js), scapi complet de definirea manuală a rutelor. Primești deep linking out-of-the-box, o chestie care la React Navigation clasic îți mânca cel puțin o zi de teste și configurări prin Xcode și Android Studio.
Trade-off-ul sincer: Expo Router merge brici dacă ai o structură clară, ierarhică. Dacă în schimb ai fluxuri extrem de dinamice — unde ecranul X se deschide complet diferit în funcție de 5 stări din Redux și vrei să controlezi fin tranzițiile native — structura de fișiere devine rigidă. Am pățit asta la un checkout complex cu vreo trei modaluri intercondiționate și a trebuit să fac niște artificii destul de urâte cu query params ca să fentez structura de foldere.
Cum configurezi Tab + Stack nested în Expo Router
Cea mai comună structură într-o aplicație de mobil este: un ecran de Login, urmat de un layout de tip Tabs (Home, Profile), iar în interiorul tab-ului Home vrei să navighezi către un ecran de Detalii (Stack), unde ideal ar fi să ascunzi sau să păstrezi tab-urile jos.
În React Navigation scriai zeci de linii de cod cu <Tab.Navigator> și <Stack.Navigator>. În Expo Router, totul se rezolvă din structura de directoare și fișiere _layout.tsx specifice fiecărui folder.
Structura ta de directoare trebuie să arate așa:
app/
├── (auth)/
│ └── login.tsx
├── (tabs)/
│ ├── _layout.tsx (aici definim tab-urile principale)
│ ├── profile.tsx
│ └── home/
│ ├── _layout.tsx (stack-ul intern pentru tab-ul Home)
│ ├── index.tsx (ecranul principal de Home)
│ └── [id].tsx (detalii produs/articol)
└── _layout.tsx (root layout cu animații globale)
Prin convenția asta, folderul (tabs) grupează ecranele care împart bara de navigare de jos. În interiorul folderului home, creăm un alt _layout.tsx care va acționa ca un Stack Navigator. Astfel, când navighezi de la home/index la home/[id], utilizatorul va vedea tranziția nativă de push-stack, dar va rămâne în contextul tab-ului de acasă.
Uită-te pe codul de mai jos ca să vezi cum configurezi tab-ul părinte. Trucul este să pui headerShown: false pe tab-ul care conține stack-ul nested, altfel te trezești cu două headere suprapuse pe ecran (unul de la tab și unul de la stack).
Am redus codul de navigare cu vreo 25% la ultimul proiect după ce am trecut pe structura asta și n-am mai avut probleme cu ecrane uitate nedeclarate. Totuși, dacă ai deja o aplicație enterprise uriașă scrisă pe React Navigation clasic, nu te arunca la refactoring doar de dragul noului. Costul migrației s-ar putea să nu se justifice dacă nu ai nevoie urgentă de deep linking stabil.
Voi ce folosiți pe proiectele curente? Vă împăcați cu file-based routing pe mobil sau preferați controlul explicit din cod?