隨著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è)邊滑出愈涩;
你可以通過以上三種導(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)=>{
}
/>
- 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)
使用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>
)
}
}
使用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' ? '正在編輯' : '編輯完成';
使用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'"
/>
)
}
}
注意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>
}
}
通過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)
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)
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)
使用場(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);
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è)問題:
- 在上文中講到過navigation中有可能只有state與dispatch所踊,這個(gè)時(shí)候如果要修改頁(yè)面的Params,則只能通過
NavigationActions.setParams
了概荷; - 另外秕岛,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í)用的哦胖腾;