隨著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 Navigation3x開發(fā)的一些實(shí)用技巧,以及從navigator到React Navigation的一些實(shí)戰(zhàn)經(jīng)驗(yàn)攒菠。
什么是導(dǎo)航器辖众?
導(dǎo)航器也可以看成一個(gè)是普通的React組件卓起,你可以通過導(dǎo)航器來定義你的App的導(dǎo)航結(jié)構(gòu)。 導(dǎo)航器還可以渲染通用元素凹炸,例如可以配置的標(biāo)題欄和選項(xiàng)卡欄戏阅。
在React Navigation中有以下7種類型的導(dǎo)航器:
- createStackNavigator: 類似于普通的Navigator,屏幕上方導(dǎo)航欄啤它;
- createTabNavigator: createTabNavigator已棄用饲握,使用createBottomTabNavigator和/或createMaterialTopTabNavigator替代;
- createBottomTabNavigator:相當(dāng)于iOS里面的TabBarController蚕键,屏幕下方的標(biāo)簽欄救欧;
- createMaterialTopTabNavigator:屏幕頂部的材料設(shè)計(jì)主題標(biāo)簽欄;
- createDrawerNavigator: 抽屜效果锣光,側(cè)邊滑出笆怠;
- createSwitchNavigator:SwitchNavigator 的用途是一次只顯示一個(gè)頁面。
你可以通過以上7種導(dǎo)航器來創(chuàng)建你APP誊爹,可以是其中一個(gè)也可以多個(gè)組合蹬刷,這個(gè)可以根據(jù)具體的應(yīng)用場景并結(jié)合每一個(gè)導(dǎo)航器的特性進(jìn)行選擇瓢捉。
在開始學(xué)習(xí)7種導(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 = createStackNavigator/createBottomTabNavigator/createMaterialTopTabNavigator/createDrawerNavigator/createSwitchNavigator({
// config
});
<SomeNav
screenProps={xxx}
ref={nav => { navigation = nav; }}
onNavigationStateChange=(prevState, newState, action)=>{
}
/>
- ref:可以通過
ref
屬性獲取到navigation
某弦; - onNavigationStateChange(prevState, newState, action):頂級節(jié)點(diǎn)除了
ref
屬性之外,還接受onNavigationStateChange(prevState, newState, action)
屬性而克,每次當(dāng)導(dǎo)航器所管理的state
發(fā)生改變時(shí)靶壮,都會回調(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í),它會收到一個(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辕录;
- addListener:訂閱導(dǎo)航生命周期的更新;
- isFocused:true 標(biāo)識屏幕獲取了焦點(diǎn)梢卸;
- getParam:獲取具有回退的特定參數(shù)走诞;
- dangerouslyGetParent:返回父導(dǎo)航器;
注意:一個(gè)navigation有可能沒有navigate蛤高、setParams以及goBack蚣旱,只有state與dispatch,所以在使用navigate時(shí)要進(jìn)行判斷戴陡,如果沒有navigate可以使用navigation去dispatch一個(gè)新的action塞绿。如:
const {navigation,theme,selectedTab}=this.props;
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
routeName: 'HomePage',
params:{
theme:theme,
selectedTab:selectedTab
},
})
]
})
navigation.dispatch(resetAction)
提示:這里的
reset
在2.0及以后版本中被從NavigationActions中移到了StackActions
中,使用時(shí)記得留意恤批。
StackNavigator的navigation的額外功能:
當(dāng)且僅當(dāng)當(dāng)前 navigator 是 stack navigator 時(shí)异吻,this.props.navigation
上有一些附加功能。 這些函數(shù)是 navigate 和 goBack 的替代方法, 你可以使用任何你喜歡的方法诀浪。 這些功能是:
- this.props.navigation
- push - 導(dǎo)航到堆棧中的一個(gè)新的路由
- pop - 返回堆棧中的上一個(gè)頁面
- popToTop - 跳轉(zhuǎn)到堆棧中最頂層的頁面
- replace - 用新路由替換當(dāng)前路由
- reset - 擦除導(dǎo)航器狀態(tài)并將其替換為多個(gè)操作的結(jié)果
- dismiss - 關(guān)閉當(dāng)前棧
使用navigate進(jìn)行界面之間的跳轉(zhuǎn)
-
navigation.navigate({routeName, params, action, key})
或navigation.navigate(routeName, params, action)
- routeName:要跳轉(zhuǎn)到的界面的路由名棋返,也就是在導(dǎo)航其中配置的路由名;
- params:要傳遞給下一個(gè)界面的參數(shù)雷猪;
- action:如果該界面是一個(gè)navigator的話睛竣,將運(yùn)行這個(gè)sub-action;
- key:要導(dǎo)航到的路由的可選標(biāo)識符求摇。 如果已存在射沟,將后退到此路由;
export const AppStackNavigator = createStackNavigator({
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>
)
}
}
在使用React Navigation3x過程中遇到任何問題都可以在React Navigation3x的視頻教程中尋找答案哈月帝。
使用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
來更新頁面頂部的標(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)前頁面的Params,如果要改變其他頁面的Params可以通過NavigationActions.setParams完成准潭,下文會講到趁俊。
在使用React Navigation3x過程中遇到任何問題都可以在React Navigation3x的視頻教程中尋找答案哈。
使用goBack返回到上一頁面或指定頁面
-
goBack: function goBack(key)
:我們可以借助goBack
返回到上一頁或者路由棧的指定頁面刑然。- 其中
key
表示你要返回到頁面的頁面標(biāo)識如id-1517035332238-4
寺擂,不是routeName。 - 可以通過指定頁面的
navigation.state.key
來獲得頁面的標(biāo)識泼掠。 - 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={{flex: 1, backgroundColor: "gray",}}>
<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择镇,會替換原來的跳轉(zhuǎn)挡逼,回退等事件。
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
routeName: 'HomePage',
params:{
theme:theme,
selectedTab:selectedTab
},
})
]
})
navigation.dispatch(resetAction)
NavigationActions
- Navigate : 導(dǎo)航到其他的頁面腻豌;
- Back : 返回到上一個(gè)頁面家坎;
- Set Params : 設(shè)置指定頁面的Params;
- Init : 初始化一個(gè) state 如果 state 是 undefined吝梅;
Navigate:
Navigatie action會使用Navigate action的結(jié)果來更新當(dāng)前的state虱疏。
方法原型:
navigate({routeName, params, action, key})
- routeName:字符串,必選項(xiàng)苏携,在app的router里注冊的導(dǎo)航目的地的routeName订框。
- params:對象,可選項(xiàng)兜叨,融合進(jìn)目的地route的參數(shù)穿扳。
- actions:對象衩侥,可選項(xiàng)(高級),如果screen也是一個(gè)navigator矛物,次級action可以在子router中運(yùn)行茫死。在文檔中描述的任何actions都可以作為次級action。
- key:
string or null
可選履羞,要導(dǎo)航到的路由的標(biāo)識符峦萎。如果已存在, 則導(dǎo)航回此路由。
import { NavigationActions } from 'react-navigation'
const navigateAction = NavigationActions.navigate({
routeName: 'Profile',
params: {},
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)
Back
返回到前一個(gè)screen并且關(guān)閉當(dāng)前screen.backaction creator接受一個(gè)可選的參數(shù):
方法原型:
back(key)
- key:
String
可選忆首,這個(gè)可以和上文中講到的goBack的key是一個(gè)概念爱榔;
import { NavigationActions } from 'react-navigation'
const backAction = NavigationActions.back();
this.props.navigation.dispatch(backAction);
SetParams
通過SetParams我們可以修改指定頁面的Params。
- params:對象糙及,必選參數(shù)详幽,將會被合并到已經(jīng)存在頁面的Params中。
- key:字符串浸锨,必選參數(shù)唇聘,頁面的key。
import { NavigationActions } from 'react-navigation'
const setParamsAction = NavigationActions.setParams({
params: { title: 'HomePage' },
key: 'id-1517035332238-4',
});
有很多小伙伴可能會問:navigation中有setParams為什么還要有NavigationActions.setParams?
我從兩方面來回答一下這個(gè)問題:
- 在上文中講到過navigation中有可能只有state與dispatch柱搜,這個(gè)時(shí)候如果要修改頁面的Params迟郎,則只能通過
NavigationActions.setParams
了; - 另外聪蘸,navigation.setParams只能修改當(dāng)前頁面的Params宪肖,而
NavigationActions.setParams
可以修改所有頁面的Params;
在使用React Navigation3x過程中遇到任何問題都可以在React Navigation3x的視頻教程中尋找答案哈健爬。
StackActions
- Reset : 重置當(dāng)前 state 到一個(gè)新的state匈庭;
- Replace : 使用另一個(gè)路由替換指定的路由;
- Push : 在堆棧頂部添加一個(gè)頁面浑劳,然后跳轉(zhuǎn)到該頁面阱持;
- Pop : 跳轉(zhuǎn)到上一個(gè)頁面;
- PopToTop : 跳轉(zhuǎn)到堆棧最頂層的頁面魔熏,并銷毀其他所有頁面;
Reset:
Reset action刪掉所有的navigation state并且使用這個(gè)actions的結(jié)果來代替镶骗。
- index,數(shù)組鼎姊,必選,navigation state中route數(shù)組中激活route的index相寇。
- actions慰于,數(shù)組,必選項(xiàng)唤衫,Navigation Actions數(shù)組婆赠,將會替代navigation state。
- key:
string or null
可選佳励, 如果設(shè)置休里,具有給定 key 的導(dǎo)航器將重置。 如果為null赃承,則根導(dǎo)航器將重置妙黍。
import { NavigationActions, StackActions } from 'react-navigation'
const resetAction = StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({ routeName: 'Profile'})
]
})
this.props.navigation.dispatch(resetAction)
使用場景比如進(jìn)入APP首頁后的splash頁不在使用,這時(shí)可以使用
NavigationActions.reset
重置它瞧剖。
index參數(shù)被用來定制化當(dāng)前激活的route拭嫁。舉個(gè)例子:使用兩個(gè)routes WelcomePage和HomePage給一個(gè)基礎(chǔ)的stack navigation設(shè)置。為了重置route到HomePage筒繁,但是在堆棧中又存放在WelcomePage之上噩凹,你可以這么做:
import { NavigationActions, StackActions } from 'react-navigation'
const resetAction = StackActions.reset({
index: 1,
actions: [
NavigationActions.navigate({ routeName: 'WelcomePage'}),
NavigationActions.navigate({ routeName: 'HomePage'})
]
});
this.props.navigation.dispatch(resetAction);
replace
Replace - 用另一個(gè)路由替換指定的路由
- key - string - 被替換的路由的 key巴元,如果未指定毡咏,最近的路由將會被替換
- newKey - string - 用于替換路線的 Key。 如果未提供逮刨,則自動生成呕缭。
- routeName - string - routeName用于替換路由。
- params - object - 要傳入替換路由的參數(shù)修己。
- action - object - 可選的子動作恢总。
- immediate* - boolean - 目前沒有效果, 這是 stack navigator 支持動畫替換(它目前不支持)的占位符。
push
Push - 在堆棧頂部添加一條路由睬愤,并導(dǎo)航至該路由. 與navigate的區(qū)別在于片仿,如果有已經(jīng)加載的頁面,navigate方法將跳轉(zhuǎn)到已經(jīng)加載的頁面尤辱,而不會重新創(chuàng)建一個(gè)新的頁面砂豌。 push 總是會創(chuàng)建一個(gè)新的頁面,所以一個(gè)頁面可以被多次創(chuàng)建
- routeName - string - routeName用于替換路由光督。
- params - object - 將合并到目標(biāo)路由的參數(shù)(通過this.props.navigation.state.params在目標(biāo)路由獲妊艟唷)。
- action - Object - 可選 - (高級)如果頁面是 navigator结借,則是在子路由器中運(yùn)行的子操作。
import { StackActions } from 'react-navigation';
const pushAction = StackActions.push({
routeName: 'Profile',
params: {
myUserId: 9,
},
});
this.props.navigation.dispatch(pushAction);
pop
The pop 一個(gè)可以返回到堆棧中上一個(gè)路由到方法圃酵,通過設(shè)置參數(shù) n球恤,可以指定返回的多少層咽斧。
- n - number - 返回的層數(shù)
import { StackActions } from 'react-navigation';
const popAction = StackActions.pop({
n: 1,
});
this.props.navigation.dispatch(popAction);
popToTop
popToTop 一個(gè)可以直接跳轉(zhuǎn)到堆棧最頂層张惹,并銷毀其它所有頁面的方法,它在功能上與StackActions.pop({n:currentIndex})
相同坎匿。
import { StackActions } from 'react-navigation';
this.props.navigation.dispatch(StackActions.popToTop());
如何支持Schema跳轉(zhuǎn)替蔬?
還有那些應(yīng)用場景承桥?
在導(dǎo)航器屏幕之外使用導(dǎo)航功能(巧用導(dǎo)航器的ref)
有一種場景:有的時(shí)候我們需要在導(dǎo)航器中所定義的屏幕之外使用導(dǎo)航器來做頁面跳轉(zhuǎn)凶异。
- 屏幕之間的跳轉(zhuǎn)是需要借助
navigation
來完成的剩彬; - 我們知道導(dǎo)航器中定義的屏幕可以通過
const {navigation} = this.props;
來獲取navigation
矿卑; - 那么,如果我們在非導(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)航器的頂級節(jié)點(diǎn)的
ref
屬性獲取到navigation
拗踢,當(dāng)上述代碼的AppNavigator
節(jié)點(diǎn)被渲染時(shí)巢墅,ref會被回調(diào)這是就可以獲取到navigation
了,需要提醒大家的是君纫,這種用法對除StackNavigator
之外的其他兩種類型的導(dǎo)航器也是實(shí)用的哦蓄髓;
- 大家在學(xué)習(xí)使用React Navigation3x過程中遇到任何問題都可以在React Navigation3x的視頻教程中尋找答案哈会喝。
- 另外肢执,也可以通過最新版React Native+Redux打造高質(zhì)量上線App視頻教程學(xué)習(xí)React Navigation3x開發(fā)的更多實(shí)戰(zhàn)經(jīng)驗(yàn)和技巧预茄,以及優(yōu)化思路临庇。