// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
export default function TabLayout() {
return (
<Tabs screenOptions={{ headerShown: false }}>
<Tabs.Screen
name="home"
options={{ title: 'Acasă' }}
/>
<Tabs.Screen
name="settings"
options={{ title: 'Setări' }}
/>
</Tabs>
);
}
// app/(tabs)/home/_layout.tsx
import { Stack } from 'expo-router';
export default function HomeStack() {
return (
<Stack>
<Stack.Screen name="index" options={{ title: 'Feed' }} />
<Stack.Screen name="details" options={{ title: 'Detalii Produs' }} />
</Stack>
);
}Am lucrat cu React Navigation de când a apărut, cred că de prin 2017. E standardul industriei, n-avem ce discuta, dar mereu m-a zgâriat pe creier configurarea aia mamut pentru deep linking. Recent, la un proiect de e-commerce cu vreo 12 ecrane și fluxuri de checkout destul de dubioase, am zis să fac pasul spre Expo Router v3. Voiam să văd dacă promisiunea de „file-based routing” chiar ne scapă de boilerplate-ul ăla infinit.
Sincer, prima oră a fost un șoc cultural. Dacă ești obișnuit să ai un singur fișier AppNavigator.tsx unde vezi tot fluxul dintr-o privire, în Expo Router te simți puțin pierdut printre foldere. Dar după ce te obișnuiești cu ideea că folderul este, de fapt, definiția rutei, lucrurile încep să se lege mult mai natural.
De ce ai face migrarea asta acum?
Cel mai mare avantaj pe care l-am simțit a fost la deep linking. La proiectul ăsta, am economisit probabil vreo 2 zile de muncă brută (și mulți nervi) pentru că nu a mai trebuit să mapăm manual URL-urile către componente. Expo Router face asta out-of-the-box. Dacă ai un fișier în app/user/[id].tsx, link-ul myapp://user/123 merge instant. Fără obiecte de configurare de 200 de linii în care sigur uiți o virgulă sau un ID.
Un alt plus e că forțează o structură curată a proiectului. Nu mai poți să arunci ecranele la grămadă. Totuși, trade-off-ul e real: ești legat de ecosistemul Expo. Dacă ai un proiect „bare” foarte customizat, s-ar putea să te lovești de niște limitări la nivel de configurare fină a stack-ului nativ, deși în 90% din cazuri nu vei simți lipsa.
Cum configurezi Tab-uri cu Stack-uri nestuite
Aici e unde se încurcă majoritatea lumii. În React Navigation clasic, făceai un createBottomTabNavigator, apoi în fiecare tab puneai un alt createStackNavigator. În Expo Router, folosim grupuri (folderele alea cu paranteze rotunde care nu apar în URL).
Structura mea arată cam așa: ai un folder (tabs) care conține un _layout.tsx. În interiorul acestui folder, fiecare tab poate fi un alt folder cu propriul lui _layout.tsx dacă ai nevoie de un stack intern. Am pățit să mă lupt cu „header doubling” (două headere suprapuse), pentru că uitasem să dau headerShown: false pe layout-ul părinte. E o greșeală clasică de care m-am lovit de vreo 3 ori până s-a fixat.
Experiența cu performanța și bundle size
La capitolul performanță, n-am văzut diferențe masive de FPS, dar am observat o îmbunătățire de cam 15% la viteza de dezvoltare (DX). Faptul că adaugi un fișier și ruta există deja e un flow mult mai apropiat de Next.js. Totuși, ai grijă la rutele dinamice. Dacă ai prea multe, devine greu să urmărești fluxul de date doar uitându-te în file tree.
Un aspect care m-a enervat la început a fost gestionarea stării între tab-uri. În React Navigation era mai direct să pasezi parametri între navigatoare. Aici, te bazezi mult mai mult pe URL params sau pe un state manager extern (Zustand e sfânt aici). Dacă vrei să trimiți un obiect complex între ecrane prin navigare, Expo Router te cam obligă să regândești totul în jurul ID-urilor din URL, ceea ce, tehnic, e „best practice”, dar uneori e pur și simplu mai lent de implementat.
Merită migrarea? Dacă începi un proiect nou, aș zice 100% da. Dacă ai un app deja stabil pe React Navigation, nu te arunca direct. Costul refactorizării layout-urilor și mutarea logicii din headere s-ar putea să nu justifice câștigul de timp imediat. Voi ce ați ales pentru ultimul proiect, ați rămas pe abordarea clasică sau ați trecut pe file-based?