react-navigation
假期學習 React Native(簡稱RN),移動端沒有像 Web 一樣自帶導航功能, react-navigation 是RN推薦的移動端導航工具。因 react-navigation 官網是英文網站,在此記錄一下自己的學習過程和自己的理解。
安裝
參考官網安裝,需要額外安裝配置的項目比較多,要特別注意。
開始
類型
導航有 stack navigator、tab navigator、drawer navigator 等幾種。
- stack navigator 堆棧導航,顧名思義,頁面會像堆棧一樣可以壓入、彈出
- tab navigator 標簽導航,頁面之間可以平行的切換,例如微信頁腳的幾個標簽可以在【微信】【通訊錄】【發現】【我】之間切換
- drawer navigator 抽屜導航,可以從屏幕的側面划出的
思想
Screen & Navigator
使用 react-navigation 開發 APP 的主要思想是,我們可以獨立開發每個頁面(稱為 Screen),然后,根據需要選擇 react-navigation 中不同類型的導航,把頁面組織起來(對應的是 Navigator)。
示例如下,導航將組織了兩個頁面 HomeScreen
和 DetailsScreen
function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
route & navigation
react-navigation 給每個頁面 (Screen) 傳入了兩個對象,可以通過 this.props.route
、this.props.navigation
調用。
-
route 主要是一些關於路由的信息
-
navigation 主要提供了一些頁面跳轉的方法
嵌套
另外,導航還可以嵌套,例如可以 stack navigator 作為 Screen 嵌入到 tab navigator。做的頁面(Screen)多了,我們就希望將頁面合理的組織起來,樹形結構是一個不錯的選擇。使用嵌套導航,可以達到這個目的。
頁面跳轉
-
navigation.navigate('RouteName')
RouteName 可以是使用 React Navigation 定義的任意的 Screen name
-
navigation.goBack() 回退
-
navigation.popToTop() 回退到第一個 Screen
-
等
傳參
-
頁面跳轉時傳參:navigation.navigate 與 navigation.push 可以傳參,如
navigation.navigate('RouteName', {paramName: 'value'})
-
頁面內部設置參數
navigation.setParams()
-
在 Screen 上可以設置初始參數
<Stack.Screen name="Details" component={Details} initialParams={{itemId:42}} />
-
接收參數
this.props.route.params?.itemId
自定義導航部件
stack navigation 默認提供一個頭部(Header)(即在頁面頂部顯示Screen.name),而 tab navigation 默認提供一個底部標簽欄,這些都是可以自定義的。
關於嵌套
機制
-
每個 Navigator 維護自己的導航歷史
-
跳轉(navigate)動作由其所在的 Nabigator 進行處理,如果無法處理,將冒泡到上一層的 Navigator 進行處理
(所以在跳轉時可以不考慮導航的結構而直接寫要跳轉的頁面名稱)
-
每個 Navigator 的特定的跳轉方法,可以被其子 Navigator 調用
注:stack navigator、tab navigator、drawer navigator 既有通用的跳轉方法如
navigation.navigate
,也有每種 nabigator 自己特有的跳轉方法。 -
父Navigator的UI將顯示在子Navigator之上,即子Nabigator是顯示在父Nabigator之中的,即在界面上也顯示出嵌套的效果。
注:如果共用 Header 或 Footer 時,可以考慮使用嵌套,否則就不要用嵌套。
嵌套中的跳轉頁面
// examples
navigation.navigate('Root');
navigation.navigate('Root', { screen: 'Settings' });
navigation.navigate('Root', {
screen: 'Settings',
params: { user: 'jane' },
});
navigation.navigate('Root', {
screen: 'Settings',
params: {
screen: 'Sound',
params: { screen: 'Media' },
},
});
嵌套的最佳實踐
- 盡量減少嵌套,嵌套可能導致的問題:
- 編碼困難
- 內存消耗、性能下降
- 用戶體驗差
- 嵌套的導航是實現一種界面設計的方法,而不是用來組織代碼的方法。
生命周期
與 React 相關聯的生命周期
假設在 stack navigator 中有,頁面A,頁面B。
-
進入頁面A,調用
A.componentDidMount
-
進入頁面B,調用
B.componentDidMount
-
離開頁面B,調用
B.componentWillUnmount
-
離開頁面A,調用
A.componentWillUnmount
React Navigation 生命周期的事件
focus
進入頁面blur
離開頁面
例子:
使用 addEventListener
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// Screen was focused
// Do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
使用 useFocusEffect
import { useFocusEffect } from '@react-navigation/native';
function Profile() {
useFocusEffect(
React.useCallback(() => {
// Do something when the screen is focused
return () => {
// Do something when the screen is unfocused
// Useful for cleanup functions
};
}, [])
);
return <ProfileContent />;
}