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的功能。

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

安裝的相關說明,請詳參

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

Drawer navigator

Stack navigator

Tab navigator

Redux