Expo Router 入門:用資料夾結構,做出多頁面導航
這是「接下來可以學什麼」系列的第二篇。內容已對照 Expo 官方文件(docs.expo.dev)整理,說明 Expo Router 目前的核心觀念與用法。
一、為什麼需要「導航」?
一個 App 通常不會只有一個畫面。例如一個簡單的社群 App,可能會有:首頁、個人頁面、設定頁面,使用者要能在這些畫面之間切換、返回上一頁、點擊某個項目進入詳細頁面。
「導航(Navigation)」指的就是:管理使用者在不同畫面之間移動的邏輯。
在傳統 React Native 開發中,導航通常需要自己手動設定一套導航邏輯,對新手來說有點複雜。Expo Router 的出現,就是讓這件事變得更直覺、更簡單。
二、Expo Router 的核心概念:資料夾結構=畫面結構
Expo Router 最大的特色,是採用「檔案式路由(File-based Routing)」。
簡單說:你的資料夾長什麼樣子,App 的頁面結構就長什麼樣子,不需要額外寫一份「設定檔」去描述哪個網址對應哪個畫面。
舉個例子,如果你的專案裡有這樣的結構:
app/
├─ _layout.tsx
├─ index.tsx
├─ home.tsx
└─ profile/
└─ friends.tsx
對應的意思是:
app/index.tsx→ App 打開時看到的第一個畫面(網址是/)。app/home.tsx→ 一個畫面,網址是/home。app/profile/friends.tsx→ 一個畫面,網址是/profile/friends。app/_layout.tsx→ 根佈局(Root Layout),會比其他畫面先被載入,是放初始化設定(例如載入字型、設定主題)的地方。
小提醒:依官方目前的範例專案結構,新版預設範本可能會把這些檔案放在
src/app/資料夾底下(多了一層src),實際路徑請依照你專案產生時的結構為準,概念完全相同。
三、認識幾個重要的「特殊命名規則」
Expo Router 用檔名和資料夾名稱的「寫法」,來決定這個畫面的行為,新手務必先認識下面幾種:
1. index.tsx:該資料夾的預設首頁
如果 app/profile/index.tsx 存在,使用者進入 /profile 時,預設就會看到這個畫面。
2. _layout.tsx:佈局檔案,不是真正的畫面
_layout.tsx 不會自己變成一個頁面,而是定義這一層資料夾底下的畫面,要用什麼方式組織(例如要用堆疊導航、還是底部標籤)。
// app/_layout.tsx
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
);
}
3. (小括號):路由群組,不影響網址
資料夾名稱用小括號包起來,例如 (tabs),代表這是一個「分組用」的資料夾,不會出現在實際網址裡。
例如 app/(tabs)/index.tsx,網址仍然是 /,不會變成 /tabs/。這種寫法常用來把「同一組標籤頁面」放在一起管理,但又不想讓網址多一層。
4. [中括號]:動態路由(可變的網址參數)
如果檔名是 [id].tsx,代表這個網址裡有一段是「變動的」,例如:
app/post/[id].tsx
對應到 /post/1、/post/2、/post/abc 等等不同網址,都會跑到同一個畫面,差別只是你可以在程式裡取出 id 這個參數,去抓對應的資料。
四、實作練習:做出底部標籤導航(Tabs)
底部標籤(像很多 App 下方那排「首頁/搜尋/我的」)是最常見的導航方式之一,用 Expo Router 做起來非常直覺。
步驟 1:把要放進標籤的畫面,放進一個用小括號命名的資料夾
app/
├─ _layout.tsx
└─ (tabs)/
├─ _layout.tsx
├─ index.tsx ← 首頁
└─ settings.tsx ← 設定頁
步驟 2:在根佈局,指向這個標籤群組
// app/_layout.tsx
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
</Stack>
);
}
步驟 3:在 (tabs)/_layout.tsx 裡,定義標籤列
// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
export default function TabLayout() {
return (
<Tabs>
<Tabs.Screen name="index" options={{ title: '首頁' }} />
<Tabs.Screen name="settings" options={{ title: '設定' }} />
</Tabs>
);
}
完成以上三步,存檔之後,你的 App 下方就會出現「首頁」「設定」兩個標籤,點擊就能切換畫面,完全不需要自己處理切換邏輯,Expo Router 都幫你做好了。
補充:官方文件目前提供三種標籤做法──JavaScript Tabs(上面範例這種,最常見、最快上手)、Native Tabs(直接使用 iOS / Android 系統內建的標籤列,外觀更原生)、Custom Tabs(完全自己設計外觀)。新手建議先從 JavaScript Tabs 開始熟悉概念,之後有需要再換成 Native Tabs 追求更原生的外觀。
五、畫面之間怎麼互相跳轉?
Expo Router 提供兩種常見方式,讓使用者從一個畫面跳到另一個畫面。
方式 1:用 <Link> 元件(像網頁的超連結)
import { Link } from 'expo-router';
import { View } from 'react-native';
export default function Home() {
return (
<View>
<Link href="/profile/friends">查看我的朋友</Link>
</View>
);
}
方式 2:用 router.push()(在程式邏輯裡跳轉,例如按鈕點擊後)
import { router } from 'expo-router';
import { Pressable, Text } from 'react-native';
export default function Home() {
return (
<Pressable onPress={() => router.push('/profile/friends')}>
<Text>查看我的朋友</Text>
</Pressable>
);
}
兩種方式效果相同,差別只是寫法上的選擇:畫面上單純的連結,習慣用 <Link>;需要先做一些判斷(例如先驗證表單再跳轉)才決定要不要跳頁,習慣用 router.push()。
六、新手常見問題
Q:一定要用小括號 (tabs) 嗎?
不一定。小括號資料夾只是用來「分組但不影響網址」,如果你不在意網址多一層,也可以不用小括號,單純當作一般資料夾使用。
Q:_layout.tsx 可以巢狀(一層一層)使用嗎?
可以,而且非常常見。例如根目錄有一個 _layout.tsx 管理整體外觀,(tabs) 資料夾裡又有自己的 _layout.tsx 管理標籤列,每往下一層資料夾,都可以再加一層佈局邏輯,做出更複雜的導航結構(例如某個標籤裡面又有自己的堆疊導航)。
Q:忘記某個畫面該放哪裡,網址會跑到哪? 建議養成習慣:先想清楚「這個畫面的網址應該是什麼」,再決定資料夾路徑,因為 Expo Router 是直接照著資料夾路徑去對應網址的,路徑想清楚了,程式碼結構自然就會對。
七、小結
- Expo Router 用資料夾結構直接對應畫面結構,不用額外寫設定檔。
index.tsx是預設首頁,_layout.tsx是佈局檔,(小括號)是不影響網址的分組資料夾,[中括號]是可變參數的動態路由。- 想做底部標籤,就用
(tabs)資料夾搭配Tabs元件;想跳頁,用<Link>或router.push()。
把上面的標籤導航範例自己跑一次、加一個自己的第三個標籤試試看,會比單純看文字理解更快。下一篇,我們會接著介紹 React Native 常用元件:View、Text、Image、FlatList、Pressable。