從navigator到react-navigation進(jìn)階教程

隨著react-navigation逐漸穩(wěn)定香府,Navigator也被光榮的退休了双絮。在React Native生態(tài)環(huán)境中需要一款可擴(kuò)展且易于使用的導(dǎo)航組件,Navigator 自然勝任不了,這時(shí)React Native社區(qū)便孕育出了一個(gè)開源導(dǎo)航組件react-navigation

react-navigation的出現(xiàn)替代了Navigator敦跌、 Ex-Navigation等老一代的導(dǎo)航組件,react-navigation可以說是Navigator的加強(qiáng)版逛揩,不僅有Navigator的全部功能柠傍,另外還支持底部導(dǎo)航類似于與iOS中的UITabBarController麸俘,此外它也支持側(cè)拉效果方式的導(dǎo)航類似于Android中的抽屜效果。

這篇文章將向大家分享react-navigation的一些實(shí)用技巧携兵,以及從navigator到react-navigation的一些實(shí)戰(zhàn)經(jīng)驗(yàn)疾掰。另外大家也可以學(xué)習(xí)與本教程配套的視頻版:《全新導(dǎo)航器react-navigation精講》

什么是導(dǎo)航器搂誉?

導(dǎo)航器也可以看成一個(gè)是普通的React組件徐紧,你可以通過導(dǎo)航器來定義你的App的導(dǎo)航結(jié)構(gòu)。 導(dǎo)航器還可以渲染通用元素炭懊,例如可以配置的標(biāo)題欄和選項(xiàng)卡欄并级。

在react-navigation中有以下三種類型的導(dǎo)航器:

  • StackNavigator: 類似于普通的Navigator,屏幕上方導(dǎo)航欄侮腹;
  • TabNavigator: 相當(dāng)于iOS里面的TabBarController嘲碧,屏幕下方的標(biāo)簽欄;
  • DrawerNavigator: 抽屜效果父阻,側(cè)邊滑出愈涩;
react-navigation

你可以通過以上三種導(dǎo)航器來創(chuàng)建你APP,可以是其中一個(gè)也可以多個(gè)組合加矛,這個(gè)可以根據(jù)具體的應(yīng)用場(chǎng)景并結(jié)合每一個(gè)導(dǎo)航器的特性進(jìn)行選擇履婉。

在開始學(xué)習(xí)三種導(dǎo)航器之前,我們需要先了解兩個(gè)和導(dǎo)航關(guān)于概念:

  • Screen navigation prop(屏幕導(dǎo)航屬性):通過navigation可以完成屏幕之間的調(diào)度操作斟览,例如打開另一個(gè)屏幕毁腿;
  • Screen navigationOptions(屏幕導(dǎo)航選項(xiàng)): 通過navigationOptions可以定制導(dǎo)航器顯示屏幕的方式(例如:頭部標(biāo)題,選項(xiàng)卡標(biāo)簽等)苛茂;

導(dǎo)航器所支持的Props

const SomeNav = StackNavigator/TabNavigator/DrawerNavigator({
  // config
});

<SomeNav
  screenProps={xxx}
  ref={nav => { navigation = nav; }}
  onNavigationStateChange=(prevState, newState, action)=>{

  }
/>

@全新導(dǎo)航器react-navigation精講

  • ref:可以通過ref屬性獲取到navigation已烤;
  • onNavigationStateChange(prevState, newState, action):頂級(jí)節(jié)點(diǎn)除了ref屬性之外,還接受onNavigationStateChange(prevState, newState, action)屬性妓羊,每次當(dāng)導(dǎo)航器所管理的state發(fā)生改變時(shí)胯究,都會(huì)回調(diào)該方法;
    • prevState:變化之前的state躁绸;
    • newState:新的state裕循;
    • 導(dǎo)致state變化的action;
  • screenProps:向子屏幕傳遞額外的數(shù)據(jù)涨颜,子屏幕可以通過this.props.screenProps獲取到該數(shù)據(jù)费韭。

Screen Navigation Prop(屏幕的navigation Prop)

當(dāng)導(dǎo)航器中的屏幕被打開時(shí),它會(huì)收到一個(gè)navigation prop庭瑰,navigation prop是整個(gè)導(dǎo)航環(huán)節(jié)的關(guān)鍵一員星持,接下來就詳細(xì)講解一下navigation的作用。

navigation包含一下功能:

  • navigate:跳轉(zhuǎn)到其他界面弹灭;
  • state:屏幕的當(dāng)前state督暂;
  • setParams:改變路由的params揪垄;
  • goBack:關(guān)閉當(dāng)前屏幕;
  • dispatch:向路由發(fā)送一個(gè)action逻翁;

注意:一個(gè)navigation有可能沒有navigate饥努、setParams以及goBack,只有state與dispatch八回,所以在使用navigate時(shí)要進(jìn)行判斷酷愧,如果沒有navigate可以使用navigation去dispatch一個(gè)新的action。如:

const {navigation,theme,selectedTab}=this.props;
const resetAction = NavigationActions.reset({
    index: 0,
    actions: [
        NavigationActions.navigate({
            routeName: 'HomePage',
            params:{
                theme:theme,
                selectedTab:selectedTab
            },
        })
    ]
})
navigation.dispatch(resetAction)

@全新導(dǎo)航器react-navigation精講

使用navigate進(jìn)行界面之間的跳轉(zhuǎn)

  • navigate(routeName, params, action)
    • routeName:要跳轉(zhuǎn)到的界面的路由名缠诅,也就是在導(dǎo)航其中配置的路由名溶浴;
    • params:要傳遞給下一個(gè)界面的參數(shù);
    • action:如果該界面是一個(gè)navigator的話管引,將運(yùn)行這個(gè)sub-action士败。
export const AppStackNavigator = StackNavigator({
    HomeScreen: {
        screen: HomeScreen
    },
    Page1: {
        screen: Page1
    })

class HomeScreen extends React.Component {
  render() {
    const {navigate} = this.props.navigation;

    return (
      <View>
        <Text>This is HomeScreen</Text>
        <Button
          onPress={() => navigate('Page1', {name: 'Devio'})}
          title="Go to Page1"
        />
      </View>
     )
   }
}

@全新導(dǎo)航器react-navigation精講

使用state的params

可以通過this.props.state.params來獲取通過setParams(),或navigation.navigate()傳遞的參數(shù)褥伴。

<Button
    title={params.mode === 'edit' ? '保存' : '編輯'}
    onPress={() =>
        setParams({mode: params.mode === 'edit' ? '' : 'edit'})}
/>
<Button
    title="Go To Page1"
    onPress={() => {
        navigation.navigate('Page1',{ name: 'Devio' });
    }}
/>
const {navigation} = this.props;
const {state, setParams} = navigation;
const {params} = state;
const showText = params.mode === 'edit' ? '正在編輯' : '編輯完成';

@全新導(dǎo)航器react-navigation精講

使用setParams 改變r(jià)oute params

  • setParams: function setParams(params): 我們可以借助setParams來改變r(jià)oute params谅将,比如,通過setParams來更新頁(yè)面頂部的標(biāo)題重慢,返回按鈕等饥臂;
class ProfileScreen extends React.Component {
  render() {
    const {setParams} = this.props.navigation;
    return (
      <Button
        onPress={() => setParams({name: 'Lucy'})}
        title="Set title name to 'Lucy'"
      />
     )
   }
}

@全新導(dǎo)航器react-navigation精講

注意navigation.setParams改變的是當(dāng)前頁(yè)面的Params,如果要改變其他頁(yè)面的Params可以通過NavigationActions.setParams完成伤锚,下文會(huì)講到擅笔。

使用goBack返回到上一頁(yè)面或指定頁(yè)面

  • goBack: function goBack(key):我們可以借助goBack返回到上一頁(yè)或者路由棧的指定頁(yè)面。

    • 其中key表示你要返回到頁(yè)面的頁(yè)面標(biāo)識(shí)如id-1517035332238-4屯援,不是routeName猛们。
    • 可以通過指定頁(yè)面的navigation.state.key來獲得頁(yè)面的標(biāo)識(shí)。
    • key非必傳狞洋,也可傳null弯淘。

    navigation.state {params: {…}, key: "id-1517035332238-4", routeName: "Page1"}

export default class Page1 extends React.Component {
    render() {
        const {navigation} = this.props;
        return <View style=>
            <Text style={styles.text}>歡迎來到Page1</Text>
            <Button
                title="Go Back"
                onPress={() => {
                    navigation.goBack();
                }}
            />
        </View> 
    }
}

@全新導(dǎo)航器react-navigation精講

通過dispatch發(fā)送一個(gè)action

  • dispatch: function dispatch(action):給當(dāng)前界面設(shè)置action,會(huì)替換原來的跳轉(zhuǎn)吉懊,回退等事件庐橙。
const resetAction = NavigationActions.reset({
    index: 0,
    actions: [
        NavigationActions.navigate({
            routeName: 'HomePage',
            params:{
                theme:theme,
                selectedTab:selectedTab
            },
        })
    ]
    })
navigation.dispatch(resetAction)

@全新導(dǎo)航器react-navigation精講

NavigationActions

  • Navigate : 導(dǎo)航到其他的頁(yè)面;
  • Reset : 重置當(dāng)前 state 到一個(gè)新的state借嗽;
  • Back : 返回到上一個(gè)頁(yè)面态鳖;
  • Set Params : 設(shè)置指定頁(yè)面的Params;
  • Init : 初始化一個(gè) state 如果 state 是 undefined恶导;

Navigate:

Navigatie action會(huì)使用Navigate action的結(jié)果來更新當(dāng)前的state浆竭。

  • routeName:字符串,必選項(xiàng),在app的router里注冊(cè)的導(dǎo)航目的地的routeName邦泄。
  • params:對(duì)象删窒,可選項(xiàng),融合進(jìn)目的地route的參數(shù)顺囊。
  • actions:對(duì)象肌索,可選項(xiàng)(高級(jí)),如果screen也是一個(gè)navigator特碳,次級(jí)action可以在子router中運(yùn)行诚亚。在文檔中描述的任何actions都可以作為次級(jí)action。
import { NavigationActions } from 'react-navigation'

const navigateAction = NavigationActions.navigate({
  routeName: 'Profile',
  params: {},
  action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)

@全新導(dǎo)航器react-navigation精講

Reset:

Reset action刪掉所有的navigation state并且使用這個(gè)actions的結(jié)果來代替测萎。

  • index亡电,number,必選硅瞧,navigation state中route數(shù)組中激活route的index。
  • actions恕汇,array腕唧,必選項(xiàng),Navigation Actions數(shù)組瘾英,將會(huì)替代navigation state枣接。
import { NavigationActions } from 'react-navigation'

const resetAction = NavigationActions.reset({
  index: 0,
  actions: [
    NavigationActions.navigate({ routeName: 'Profile'})
  ]
})
this.props.navigation.dispatch(resetAction)

@全新導(dǎo)航器react-navigation精講

使用場(chǎng)景比如進(jìn)入APP首頁(yè)后的splash頁(yè)不在使用,這時(shí)可以使用NavigationActions.reset重置它缺谴。

index參數(shù)被用來定制化當(dāng)前激活的route但惶。舉個(gè)例子:使用兩個(gè)routes WelcomePage和HomePage給一個(gè)基礎(chǔ)的stack navigation設(shè)置。為了重置route到HomePage湿蛔,但是在堆棧中又存放在WelcomePage之上膀曾,你可以這么做:

import { NavigationActions } from 'react-navigation'

const resetAction = NavigationActions.reset({
    index: 1,
    actions: [
        NavigationActions.navigate({ routeName: 'WelcomePage'}),
        NavigationActions.navigate({ routeName: 'HomePage'})
    ]
});
this.props.navigation.dispatch(resetAction);

@全新導(dǎo)航器react-navigation精講

Back

返回到前一個(gè)screen并且關(guān)閉當(dāng)前screen.backaction creator接受一個(gè)可選的參數(shù):

  • key:這個(gè)可以和上文中講到的goBack的key是一個(gè)概念;
import { NavigationActions } from 'react-navigation'
const backAction = NavigationActions.back();
this.props.navigation.dispatch(backAction);

SetParams

通過SetParams我們可以修改指定頁(yè)面的Params阳啥。

  • params:對(duì)象添谊,必選參數(shù),將會(huì)被合并到已經(jīng)存在頁(yè)面的Params中察迟。
  • key:字符串斩狱,必選參數(shù),頁(yè)面的key扎瓶。
import { NavigationActions } from 'react-navigation'
const setParamsAction = NavigationActions.setParams({
    params: { title: 'HomePage' },
    key: 'id-1517035332238-4',
});

有很多小伙伴可能會(huì)問:navigation中有setParams為什么還要有NavigationActions.setParams?

我從兩方面來回答一下這個(gè)問題:

  1. 在上文中講到過navigation中有可能只有state與dispatch所踊,這個(gè)時(shí)候如果要修改頁(yè)面的Params,則只能通過NavigationActions.setParams了概荷;
  2. 另外秕岛,navigation.setParams只能修改當(dāng)前頁(yè)面的Params,而NavigationActions.setParams可以修改所有頁(yè)面的Params;

還有那些應(yīng)用場(chǎng)景瓣蛀?

在導(dǎo)航器屏幕之外使用導(dǎo)航功能(巧用導(dǎo)航器的ref)

有一種場(chǎng)景:有的時(shí)候我們需要在導(dǎo)航器中所定義的屏幕之外使用導(dǎo)航器來做頁(yè)面跳轉(zhuǎn)陆蟆。

  • 屏幕之間的跳轉(zhuǎn)是需要借助navigation來完成的;
  • 我們知道導(dǎo)航器中定義的屏幕可以通過const {navigation} = this.props;來獲取navigation惋增;
  • 那么叠殷,如果我們?cè)诜菍?dǎo)航器中所定義的屏幕中做屏幕跳轉(zhuǎn)的關(guān)鍵一步,就是要想法獲取navigation诈皿;
  • 那么林束,如何才能在非導(dǎo)航器中所定義的屏幕中獲取到這個(gè)navigation呢?

下面就給大家講解通過ref屬性還獲得navigation

示例看代碼:

import { NavigationActions } from 'react-navigation';

const AppNavigator = StackNavigator(SomeAppRouteConfigs);

class App extends React.Component {
  someEvent() {
    // call navigate for AppNavigator here:
    this. navigation && this. navigation.dispatch(
      NavigationActions.navigate({ routeName: someRouteName })
    );
  }
  render() {
    return (
      <AppNavigator ref={nav => { navigation = nav; }} />
    );
  }
}

上述代碼通過導(dǎo)航器的頂級(jí)節(jié)點(diǎn)ref屬性獲取到navigation稽亏,當(dāng)上述代碼的AppNavigator節(jié)點(diǎn)被渲染時(shí)壶冒,ref會(huì)被回調(diào)這是就可以獲取到navigation了,需要提醒大家的是截歉,這種用法對(duì)除StackNavigator之外的其他兩種類型的導(dǎo)航器也是實(shí)用的哦胖腾;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瘪松,隨后出現(xiàn)的幾起案子咸作,更是在濱河造成了極大的恐慌,老刑警劉巖宵睦,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件记罚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡壳嚎,警方通過查閱死者的電腦和手機(jī)桐智,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烟馅,“玉大人说庭,你說我怎么就攤上這事”涸悖” “怎么了口渔?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)穿撮。 經(jīng)常有香客問我缺脉,道長(zhǎng),這世上最難降的妖魔是什么悦穿? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任攻礼,我火速辦了婚禮,結(jié)果婚禮上栗柒,老公的妹妹穿的比我還像新娘礁扮。我一直安慰自己知举,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布太伊。 她就那樣靜靜地躺著雇锡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪僚焦。 梳的紋絲不亂的頭發(fā)上锰提,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音芳悲,去河邊找鬼立肘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛名扛,可吹牛的內(nèi)容都是我干的谅年。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼肮韧,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼融蹂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惹苗,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤殿较,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后桩蓉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡劳闹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年院究,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片本涕。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡业汰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菩颖,到底是詐尸還是另有隱情样漆,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布晦闰,位于F島的核電站放祟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏呻右。R本人自食惡果不足惜跪妥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望声滥。 院中可真熱鬧眉撵,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至污朽,卻和暖如春散吵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膘壶。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工错蝴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颓芭。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓顷锰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亡问。 傳聞我的和親對(duì)象是個(gè)殘疾皇子官紫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容