跳至主要内容

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 提供兩種常見方式,讓使用者從一個畫面跳到另一個畫面。

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 常用元件:ViewTextImageFlatListPressable