react-navigation使用介紹及UI元件外實現統一跳轉

不變旋律發表於2018-03-01

react-navigation是React Native中非常著名的一個頁面導航庫,可以實現各種頁面跳轉,它是React Native社群總結出來的精華。有了這個庫,我們可以實現類似iOS中UINavigationController的導航效果、常見的tabBar頁面和Android中側滑Drawer的效果,非常方便好用。

本篇文章主要介紹react-navigation的基本功能,以及一個我在實際運用中遇到的問題和解決方案,將這個方案分享一下,也許有人會遇到同樣的問題可能用得上。

react-navigation的三大元件

這裡說的三大元件其實是react-navigation的三個基本的navigation元件

StackNavigator——包含導航欄的頁面導航元件,可以實現類似iOS端UINavigationController的導航效果。在iOS中頁面跳轉效果就是push和pop的方式,Android中就是modal的方式從底部彈起一個頁面返回時dismiss。

TabNavigator——底部展示tabBar的頁面導航元件,這個頁面效果在app中是最常見的了。

DrawerNavigator——實現側邊欄抽屜頁面的導航元件,這種頁面設計效果也是非常常用的。

在之前的文章中也簡單用到了TabNavigator和StackNavigator實現電影demo。通過以上三種Navigator元件的組合使用,我們可以實現絕大多數情況下的頁面導航,應付日常開發的各種場景基本上沒問題。

react-navigation功能點

三大基本Navigator元件的使用可以查閱官方文件,有簡單的demo示例,這裡不多贅述。除此之外,官方文件還更新了不少東西,這比起之前我剛使用它的時候豐富了太多,隨著react-navigation的迭代升級,這個庫會越來越完善,下面來看看官方文件中有哪些乾貨。

iPhone X support

iPhone X與之前的iPhone都不一樣,螢幕頂部多了個劉海,底部home鍵被橫條(Home Indicator)取代,解析度提升,導航欄和狀態列高度都改變了。在適配時需要使頂部標題不被劉海遮蓋,底部內容不被橫條覆蓋。這一點react-navigation也考慮到了,新增了SafeAreaView元件來解決UI適配問題。這一點官方文件有詳細示例reactnavigation.org/docs/handli…

在使用SafeAreaView時需要注意,並不是說你把所有的UI元件都放到SafeAreaView裡面,然後render函式返回一個SafeAreaView元件就沒問題了。這要看情況而定,可以參考react-navigation官方demo

根據route設定狀態列的樣式

在iOS中狀態列有兩種樣式,default和light-content,在頁面切換時不同的頁面要顯示不同顏色,狀態列顏色顯示對應的樣式會使UI看起來更加協調美觀。這裡就講到了怎樣配置狀態列樣式Different status bar configuration based on route

Android實體返回鍵的處理

在Android中經常使用點選實體返回鍵的方式返回到上個頁面,可以通過監聽的方式捕獲使用者點選返回鍵的事件,根據實際情況來決定是否要立即返回上一個頁面。

在子元件中獲取頁面的navigation

假設一個頁面A中嵌入了頁面B和C,頁面A和頁面D是由StackNavigator控制的。如果想要點選頁面B中的一個button跳轉到頁面D,頁面B需要獲取到A中的navigation才能跳轉。因為B是一個子元件,它並不直接由StackNavigator控制,得不到這個navigation屬性就無法做跳轉。react-navigation中使用withNavigation解決了這個問題。

import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';

class MyBackButton extends React.Component {
  render() {
    return <Button title="Back" onPress={() => { this.props.navigation.goBack() }} />;
  }
}

// withNavigation returns a component that wraps MyBackButton and passes in the
// navigation prop
export default withNavigation(MyBackButton);
複製程式碼

Deep Linking

假設有這樣一個場景,在瀏覽器中點選了一個連結要跳轉到你自己的app中某個特定的頁面,該怎麼處理呢?react-navigation官方文件以StackNavigator為例講解了如何處理外部uri來進行指定頁面的跳轉。

頁面跟蹤(Screen tracking)

官方文件以Google Analytics為例講解了怎樣使用第三方SDK進行頁面跟蹤和統計。這裡推薦友盟統計,官方對react native中使用統計有文件說明。友盟統計ReactNative文件

Redux整合

官方文件詳細講解了怎樣整合Redux並使用它來管理頁面導航,github上還給出了完整的demo。可以仔細看看文件一步步整合Redux。

自定義Navigator

除了上面提到的三大Navigator元件,整合Redux管理頁面導航之外,還可以使用react-navigation中的StackRouter、TabRouter自定義Router來管理頁面導航。這部分內容是react-navigation的高階用法,可以參考官方demo,自己動手實現一個自定義頁面導航。這裡我實現了一個左側顯示tabBar控制右側頁面切換顯示的導航,用於pad端,Demo地址在這裡。pad端執行效果如下:

react-navigation使用介紹及UI元件外實現統一跳轉

UI元件外獲取navigation並統一跳轉

在使用react-navigation的過程中,我遇到一個問題。App中多個介面都需要呼叫介面獲取資料,介面必傳token引數,而token又是登入後才獲取的。假如同一個賬號在其它裝置登入,那麼當前裝置呼叫介面時必然會出現token失效導致請求失敗的情況,這就是單點登入造成的問題。如果一個頁面有兩個以上介面需要呼叫,而每個介面都會報錯,在每個地方都進行錯誤處理顯然是不明智的。

例如,介面請求失敗,我們需要重新登入,如果每個頁面,每個出錯的地方都寫跳轉程式碼,那整個專案程式碼就太冗餘了。所以對介面的業務邏輯進行處理做統一跳轉是更為合理的選擇。但是介面程式碼我們一般會封裝起來,不會寫在UI程式碼裡,怎樣才能獲取到當前正在顯示的那個介面和navigation呢?

這個問題我當時思考了很多方案,由於對react-navigation的理解和使用還沒有特別純熟,所以一時之間沒有好的解決方案,直到在stackoverflow上發現了這個問答,給出了一個有意思的解決方法,地址:stackoverflow.com/questions/4…

通過建立BaseComponent,在初始化時獲取頁面的例項,讓處於路由中的每個UI頁面都繼承於這個BaseComponent,就能在任何其它地方獲取到當前正在顯示的頁面,從而呼叫這個頁面的navigation進行跳轉。這裡並沒有用到其它框架(如Redux)就解決了這個問題。在實際專案中進行驗證後確認這個方案是可行的。我另外寫了個簡單的demo,以供參考,demo地址:github.com/mrarronz/re…

總結

react-navigation真的是非常好用的一個導航庫,官方文件更新後更加完善,給出了許多示例,學習起來更加容易上手,同時還推薦了其它庫如react-native-router-fluxreact-native-navigationreact-router-native,這些也都是非常好的開源庫。

關於頁面外獲取navigation的方法,相信隨著不斷的深入學習,一定會有更多的解決方式,解決方案少是因為我們知道的還不夠多。

PS: 順便推薦一個工具Expo,它是一個圍繞ReactNative打造的工具鏈,用來幫助我們使用JS和React建立原生的iOS和Android應用。react-navigation中的部分demo整合到Expo,Expo有安卓和iOS的客戶端app,下載安裝後,可以在Expo中通過掃二維碼的方式開啟demo直接看到執行效果,非常好用。Github上很多開源的app都整合了Expo,可以直接掃碼檢視效果,趕緊安裝吧~

相關文章