在網站中我們會設定路由表來切換頁面,同樣的在 App 中也會有頁面切換的需求,而 React Navigation 可以幫我們在 React Native 環境中設定路由。截至 2023 年 7 月為止, React Navigation 需搭配 React Native 0.63.0 以上(含)版本。若專案中有用到 TypeScript ,需要 4.1.0 以上(含)版本。
首先在終端機以 npm install @react-navigation/native @react-navigation/native-stack react-native-screens react-native-safe-area-context
下載。同時還須設定 ios ,一樣在終端機 cd ios
移動到 ios 資料夾後以 pod install
下載。
Tips :若移動到 ios 資料夾後要執行其他事,別忘了用
cd ..
移回上層資料夾後再執行。
直接用官網範例程式碼來了解路由和頁面元件怎樣設定。首先我們在 App.jsx 設定一個名為 HomeScreen 頁面元件。
import React from 'react';
import {View, Text} from 'react-native';
function HomeScreen() {
return (
<View>
<Text>Home Screen</Text>
</View>
);
}
在最上方載入 NavigationContainer 與 createNativeStackNavigator 。
NavigationContainer 是一個用來管理導覽表的元件,所有 navigator 都必須被包覆在他裡頭。通常都會在根元件中設定與渲染 NavigationContainer 。
createNativeStackNavigator 則是一個函式,會返回一個物件,包著兩個元件: Screen 和 Navigator 。藉由宣告一個變數 Stack ,可以讓我們取用這兩個元件。 Navigator 必須包在 Screen 外,用以定義路由配置;而 Screen 顧名思義負責載入路由表上的頁面元件,必須包含路由名字 name 和要渲染的元件 component 兩個屬性。
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
const Stack = createNativeStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
完成後應該就會看到最基本的頁面了:
Tips :若下載後執行範例程式碼報錯,可關閉模擬器重新開啟試試看。
Tips :調整路由表架構後,有時仍會記錄到舊的導致錯誤,可以
ctrl + c
停止專案,重新npm start
重啟。
接著可以依樣畫葫蘆製作第二個頁面元件 DetailScreen 。可以發現,當我們把 DetailScreen 的 Stack.Screen 移到 HomeScreen 之上時,畫面就會顯示 DetailScreen ;反之,則顯示 HomeScreen 。
function DetailScreen() {
return (
<View>
<Text>Detail Screen</Text>
</View>
);
}
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Detail" component={DetailScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
若我們不想靠這樣調整順序,預設第一個渲染的畫面, React Navigation 也提供 initialRouteName 屬性來設定。注意!傳入的值必須是 Screen 中設定的 name 。
<NavigationContainer>
<Stack.Navigator initialRouteName="Detail">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Detail" component={DetailScreen} />
</Stack.Navigator>
</NavigationContainer>
建立路由表後,我們要怎樣讓使用者在不同頁面間自由切換呢?首先,如果我們已經明確知道要切換過去的元件名稱, 那可以透過在頁面元件傳入 navigation 這個預設的 props ,來使用 navigation.navigate()
跳過去。注意!裡頭傳入的要是 Screen 設定的 name 。
把 HomeScreen 做以下改寫:
function HomeScreen({navigation}) {
return (
<View>
<Text>Home Screen</Text>
<TouchableOpacity onPress={() => navigation.navigate('Detail')}>
<Text>切換到 Detail Screen</Text>
</TouchableOpacity>
</View>
);
}
如果要回到上一頁,除了用手機預設的上一頁功能外,我們也可以透過 navigation.goBack()
來實踐。
function HomeScreen({navigation}) {
return (
<View>
... 省略
<TouchableOpacity onPress={() => navigation.goBack()}>
<Text>回上頁</Text>
</TouchableOpacity>
</View>
);
}
假設今天製作的頁面是一個菜單列表,點擊後進入每道菜的介紹頁面。如同之前提過的元件設計邏輯,我們不可能為每道菜製作一個頁面元件,不只會累死自己,也很難維護管理,更何況要秀的內容都一樣。
這時,就可以在點擊菜單列表上的按鈕時,傳一個參數。當進入同個介紹內頁時,再透過該參數來取 API ,秀出對應內容。在 navigation.navigate()
的第二個參數放入一個裝參數的物件,物件的屬性會是取出時使用的名稱,可自由命名,並可不只一個值。在接收參數的 Functional Component 載入 route ,並用物件解構取得包在 params 裡的參數,做後續不同內容渲染。
function HomeScreen({navigation}) {
return (
<View>
<Text>MENU</Text>
<TouchableOpacity onPress={() => navigation.navigate('Detail', {id: 0})}>
<Text>滷肉飯</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Detail', {id: 1})}>
<Text>炒米粉</Text>
</TouchableOpacity>
</View>
);
}
function DetailScreen({navigation, route}) {
const {id} = route.params;
return (
<View>
<Text>{id}</Text>
<Text>{id === 0 ? '滷肉飯' : '炒米粉'}</Text>
<TouchableOpacity onPress={() => navigation.navigate('Home')}>
<Text>切換到 Home Screen</Text>
</TouchableOpacity>
</View>
);
}
透過 console.log()
觀察 route ,會發現他是一個物件。除了傳遞參數的 params 外,還有每次點擊都隨機生成的唯一值 key ,進入的路徑名稱 name ,以及只有透過 deep link 打開才會有的路徑 path 。