Router and Navigation
Routing and Navigation
2020/12/05 (新增連結)
簡介
在react native裡,並沒有提供navigation元件,最多人使用的是React Navigation,然而,也有人使用其他的元件,例如,react native navigation。我們這裡只介紹React Navigation。
React Navigation是react native的元件,除了提供navigation之外,也提供了routing的功能。為什麼要提供routing呢? 因為react是所謂的Single Page Application,所以,上個單元的做法其實是透過隱藏頁面,來製造換頁面的效果,不是真的導向不同的頁面。React Navigation內建了routing的功能。
要使用react navigation,安裝React Navigation
npm install @react-navigation/native
使用expo,還要安裝這些套件: (詳參: Getting started )
expo install react-native-gesture-handler react-native-reanimated react-native-screens react-native-safe-area-context @react-native-community/masked-view
安裝的相關說明,請詳參
React Navigation官方文件
Navigating Between Screens (by React native)
Stack Navigator
React Navigation提供很多種navigator,最基本的就是StackNavigator,StackNavigator是將螢幕如同堆疊(stack)一樣疊起來 (詳參: createStackNavigator)。
需要安裝stack
npm install @react-navigation/stack
先將原本的App.js改個名字,新增App.js,貼上範例的內容。
import相關的套件:
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
產生一個stackNavigator變數:
const Stack = createStackNavigator();
在NavigationContainer裡定義navigator
<NavigationContainer>
<Stack.Navigator>
</Stack.Navigator>
</NavigationContainer>
在navigator裡定義screen,利用name定義Screen的名稱,利用component設定對應的元件。
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
App.js 完整程式
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
加上另一個Screen
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
這樣只能看到Home,看不到Detail。
利用navigate切換畫面
要打開另一個已經定義好的screen,就利用navigation的navigate(),navigation有很多可以使用的方法,這裡只介紹最基本的navigate(),其他方法請詳參: Moving between screens 。
在react navigation裡,利用name來設定route,接下來可以直接用這些route的名稱,透過navigation.naviate()打開這些元件,這就是為何我們說react navigation提供navigation及routing。
onPress={() => navigation.navigate('Details')}
navigation是Screen給的HomeScreen及DetailScreen的prop (詳參: Navigation prop reference ),Screen給的props裡,這裡只用到最基本的navigation。
function HomeScreen({ navigation }) {
App.js
import * as React from 'react';
import { View, Text, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import ProductList from './product/ProductList';
import Click from './Click';
function HomeScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
function DetailsScreen({ navigation }) {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Home"
onPress={() => navigation.navigate('Home')}
/>
</View>
);
}
const Stack = createStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
利用useNavigation切換畫面
有時候,無法直接利用props取得navigation,這時候,可以利用useNavigation。
import * as React from 'react';
import { View, Text, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/native';
function HomeScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Go to Details"
onPress={() => navigation.navigate('Details')}
/>
</View>
);
}
function DetailsScreen() {
const navigation = useNavigation();
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
<Button
title="Go to Home"
onPress={() => navigation.navigate('Home')}
/>
</View>
);
}
const Stack = createStackNavigator();
function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
Tab Navigator
我們來試試看不同的UI,試試看換成Tab navigation,我們使用BottomTabNavigator,所以,我們就可以利用畫面最下面的Tab來切換畫面,而不需要navigation.navigate()。另外,Tab Navigator會將name顯示在tab裡,如果要改變,請詳參: Configuring the header bar。也可以更改Tab Navigator的行為 (詳參: Header buttons )。
npm install @react-navigation/bottom-tabs
改一下程式碼:
import * as React from 'react';
import { View, Text } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
//import { createStackNavigator } from '@react-navigation/stack';
function HomeScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
</View>
);
}
function DetailsScreen() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Details Screen</Text>
</View>
);
}
//const Stack = createStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Details" component={DetailsScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
傳遞變數
試著加入ProductList到Navigator。
試著加入Click到Navigator。
怎麼傳變數進入Click? HomeScreen是Screen的子元件,所以,傳值的部分,不能利用props。(詳參: Passing parameters to routes )
App.js的內容更改:
<Tab.Screen name="Click" component={Click} initialParams={{ count: 10 }}/>
如果利用navigation.navigate
navigation.navigate('Click', {count: 10});
Click.js的內容更改:
export default function Click({route}) {
const [count, setCount] = useState(route.params.count);
Nesting navigators
在navigator裡,可以有其他的navigator。(** 待補充)
React Navigation V5 : How to create Nested Stack and tab Navigation
Adding React Navigation to Your React Native App
利用children
作業
套用themes。
常見問題
參考資料
React Navigation
useNavigation (react navigation 5)
Up and running with Expo, React Native, & React Navigation 5.0 (利用expo的tabs with react navigator template)
Lifecycle hooks are not enough with React Navigation in React Native (2020)
Navigation in React Native (2018)
Up and running with React Navigation (part 1) (2017)
React Navigation: I Like Your Style (part 2)
React Navigation: Stacks, Tabs, and Drawers … Oh my! (part 3)
Transition
Custom Transitions in React Navigation (part 4) (2017)
Routing in React Native apps and how to configure your project with React-Navigation library — 2x01 (2018, react navigation 3.x)
React Navigation documentation versions
現在已經是v5 (2020/09/07)
Hands-On: React Navigation 5 (2020)
Share state between screens with custom navigators in React Navigation (this was written with Expo 32.x & React-Navigation 3.x.)
Getting Started with React Navigation, the Navigation Solution for React Native (2017, react navigation 1,x)
Drawer navigator
React Native — Drawer Navigation : With React Navigation (2019)
Stack navigator
Tab navigator
Ricky Figures It Out: Simple React-Native TabNavigator using React-Navigation (2018)
Custom Tab Bar in React Native with react navigation (2017)