React Navigation 学习
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了React Navigation 学习,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含8980字,纯文字阅读大概需要13分钟。
内容图文
![React Navigation 学习](/upload/InfoBanner/zyjiaocheng/1155/0f6b2a07b71c4d32b6c57e71790d8ed8.jpg)
React Navigation: Android 和 iOS 设备上的路由工具,包括手势和动画。
零、环境篇
在使用 react-navigation 之前,我们需要创建一个 react-native 项目。(参考https://reactnative.cn/docs/getting-started)
一、Navigator 的种类和创建
在 web 项目中的 react-router,只负责功能实现,样式是需要开发者自己去设计的。而 react-navigation 自带了几种常见的交互和样式。它共有四种常用的 Navigator:
-
Stack 的功能与 react-router 类似,但是每一个页面有一个标题栏。
-
Switch(Switch / AnimatedSwitch) 没有样式,为鉴权场景而生。它每次只渲染一个页面,不处理返回操作,并在你切换时将路由重置为默认状态。
-
Drawer 菜单被放在一个抽屉中,通过一个在屏幕最左边的右滑手势,来打开抽屉。
-
Tab(BottomTab / MaterialBottomTab / MaterialTopTab) 菜单被放在 Tabs 中,可以在屏幕的顶部或底部。
1. 认识 create***Navigator
创建这些导航的语法都是类似的:
1 import { createAppContainer, createSwitchNavigator } from ‘react-navigation‘; 2 import { createDrawerNavigator } from ‘react-navigation-drawer‘; 3 import { createStackNavigator } from ‘react-navigation-stack‘; 4 import { createMaterialTopTabNavigator } from ‘react-navigation-tabs‘; 5 6 const navigator = create***Navigator( 7// routes 8 { 9 Home: { // 如果没有 navigation 等其他选项,也可以简写为:Home: Home10 screen: Home // 加载的组件11 navigationOptions: {}, // screen 配置12 path: ‘people/:name‘, // deep-link 或者 web应用 场景下使用13 } 14 }, 15// configs16 { 17 initialRouteName: ‘‘, // 初始路由18 navigationOptions: {}, // navigator 的配置19 defaultNavigationOptions: {}, // screens 的配置20 paths: {} // deep-link 场景21 ... 22 } 23) 24 export default createAppContainer(navigator)
2. 认识 navigationOptions
navigationOptions 可以写在 route 中,可以写在 navigator 中(3.x 开始叫 defaultNavigationOptions),也可以写在 screen 中。优先级是 route > screen > navigator。
1 ({ navigation, screenProps, navigationOptions }) => ({ // object | function2 title: ‘标题‘, // ??默认情况下按照平台惯例设置,所以在 iOS 上标题居中,在 Android 上左对齐3 headerTitle: <Title />, // 也可以设置一个组件,它可以通过 nativation.getParam、setParams 和页面通信,也可以使用 redux 等 4 headerRight: <Title />, 5 headerLeft: <Title />, // 会覆盖返回按钮 6 headerStyle: {}, // 整个标题栏7 headerTintColor: ‘‘, // 标题和返回按钮的颜色8 headerTitleStyle: {}, // 标题的样式9 })
3. 认识 createAppContainer
createAppContainer 将导航配置转变成 React 组件,这时它就可以放在项目的任何地方了。生成的组件可以接受两个属性:onNavigationStateChange 和 uriPrefix
1 const AppContainer = createAppContainer(navigator); 23 <AppContainer 4 onNavigationStateChange={(prevState, newState, action) => {}} // 监听所有的路由状态变化5 uriPrefix="/app" // deep-link 场景6 />
二、Navigation Prop 基础功能
1. 通用导航API
-
navigate ?code: props-goBack
下图说明 stackNavigator 中的 navigate 的行为。当栈内没有找到该路由对应的页面时,就推入一个新的页面,否则只是弹出到已有页面。
Drawer、Tab 中,一个路由只能有一个组件存在——底层也是 stack 实现,但 this.props.navigation.state 永远都是所有路由的集合。 -
goBack?code: props-navigate
此图说明 stackNavigator 中的 goBack 行为,传入参数表示「以我为参考进行回退」
Drawer、Tab 中,goBack 默认返回初始路由。
2. stack 专用导航API
-
push,推入页面(和 navigate 的区别是,push不会去查找栈中是否已经有该路由)
-
pop,弹出页面
-
popToTop,弹出到底部路页面
-
replace,替换
-
reset,重置当前 navigator
-
dismiss ,退出当前 navigator,返回上层 navigator ?code: props-reset-vs-dismiss
3. drawer 专用导航API
-
openDrawer
-
closeDrawer
-
toggleDrawer 控制菜单显隐
4. 其他通用的属性
-
state
-
setParams(name, value)
-
getParams(name, defaultValue)
-
isfocused() // 是否被聚焦
-
dangerouslyGetParent() // 获取父导航
-
dispatch() // 用 props.navigation.dispatch(action) 的方式去改变路由,如下图
-
addListener(eventName, ({ action, context, lastState, state, type }) => {})
5. 路由变化时组件生命周期
Stack 在路由出栈的时候,组件会被卸载。但是 Drawer、Tab 的组件不会被卸载,状态会一直保存。
三、不传属性系列
上面的这些属性都是在 screen 组件中,通过 this.props.navigation 调用的。这就意味着,如果有深层次的子组件想操作路由,screen 就需要将 navigation 作为子组件的属性传递下去。以下提供了一些不传属性也能操作路由的方法:
1. withNavigation
这是一个高阶组件,对内传递给子组件 navigation 属性,对外暴露 onRef 属性传递出子组件的引用
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();
}}
/>
);
}
}
export default withNavigation(MyBackButton);
// 使用
<MyBackButton onRef={elem => (this.backButton = elem)} />;
2. withNavigationFocus
也是一个高阶组件,对内传递给子组件 isFocused 属性。注意??,由于是属性传递,会导致组件重新渲染,需要 shouldComponentUpdate 来控制组件渲染次数。
import React from ‘react‘;
import { Text } from ‘react-native‘;
import { withNavigationFocus } from ‘react-navigation‘;
class FocusStateLabel extends React.Component {
render() {
return <Text>{this.props.isFocused ? ‘Focused‘ : ‘Not focused‘}</Text>;
}
}
export default withNavigationFocus(FocusStateLabel);
3. 全局变量
还有一种办法就是将某个 navigator 保存为全局变量,这样不同层级的页面也可以方便地互相导航。
import { NavigationActions } from ‘react-navigation‘;
let _root;
const setTopLevelNavigator = (navigatorRef) => {
_root = navigatorRef;
}
const getTopLevelNavigator = () => {
return _root
}
export default {
setTopLevelNavigator,
getTopLevelNavigator
};
const App = () => {
return (
<RootNavigator ref={navigation.setTopLevelNavigator} />
);
};
const navigator = navigation.getTopLevelNavigator();
navigator.dispatch(NavigationActions.navigate({
routeName: ‘Drawer‘,
action: DrawerActions.openDrawer()
}))
四、滴滴打车路由设计
?code: didi
-
首先,我们有一个广告页、登录页、主页的选择的场景,这三个页面是互斥的,只会存在一个,这种场景就适合用 SwitchNavigator。
-
顺风车、出租车明显是 TopTabNavigator 的交互——注意它们的上方还有一个类似标题栏的东西,这意味着可以在外面再套一层 StackNavigator(订单页也是如此)。
-
而这一层 StackNavigator 和订单页的 StackNavigator 都是属于 DrawerNavigator 的内容,于是我们就有了下图这样一个路由的结构。
五、与 React Native 配合
1. Scrollables
使用 react-native 的 ScrollView/FlatList/SectionList 的时候,有一个非常方便的交互设计:点击手机顶部的时候可以快速滚到顶部初始位置。如果想要点击 TabNavigator 的 Tab 时,也想有这种效果怎么办?可以直接使用 react-navigation 封装过的 ScrollView/FlatList/SectionList。?code: scrollables
2. SafeAreaView
react-native 的 SafeAreaView 大家都知道,可以让手机在 ios 的刘海屏/美人尖等异型屏上能正常显示。
react-navigation 提供的 SafeAreaView 则多了一个属性 forceInset,可以让我们更加精细地控制四边的padding。它在 top | bottom | left | right | vertical | horizontal 几种方向上有两种值可以设置:‘always‘ 和 ‘nerver‘。?code: safeAreaView
这里要注意的是,如果 SafeAreaView是包裹在页面上的,不包括导航栏的高度,如下图左红色部分。如果 SafeAreaView 是包裹在 RootNavigator 上的,就包括导航栏的高度,如下图右蓝色部分。当然就算我们只放在页面上,导航栏的高度也对异性屏做了兼容,使得我们的页面在ios各种机型上正常显示(react-navigation 4.x)。
那么,Android 异型屏怎么办?借助 react-native-device-info 识别是否有 notch,然后设置 SafeAreaView 的高度
1 import { Platform } from ‘react-native‘; 2 import SafeAreaView from ‘react-native-safe-area-view‘; 3 import DeviceInfo from ‘react-native-device-info‘; 4 5if (Platform.OS === ‘android‘ && DeviceInfo.hasNotch()) { 6 SafeAreaView 7 .setStatusBarHeight 8/* Some value for status bar height + notch height */ 9 (); 10 }
六、监听路由事件
NavigiationEvents 是 react-navigation 导出的一个组件,它上面有五个属性。在任何组件上都可以放置 <NavigiationEvents />,路由事件会自顶向下传导,父组件、子组件的事件处理函数会依次被触发。?code: navigationEvents
-
onWillFocus
-
onDidFocus
-
onWillBlur
-
onDidBlur
-
navigator(默认当前所处上下文)
1 import React from ‘react‘; 2 import { View } from ‘react-native‘; 3 import { NavigationEvents } from ‘react-navigation‘; 4 5 const MyScreen = () => ( 6 <View> 7 <NavigationEvents 8 onWillFocus={payload => console.log(‘will focus‘, payload)} 9 onDidFocus={payload => console.log(‘did focus‘, payload)} 10 onWillBlur={payload => console.log(‘will blur‘, payload)} 11 onDidBlur={payload => console.log(‘did blur‘, payload)} 12 /> 13 {/*14 Your view code 15*/} 16 </View> 17); 1819 export default MyScreen;
七、其他
TypeScript 支持
https://reactnavigation.org/docs/en/typescript.html
2.14.0 之前的版本使用 react-native-screens 来进行 native 侧的性能优化
https://reactnavigation.org/docs/en/react-native-screens.html
状态保持(实验性)
涉及到的 API:persistNavigationState、loadNavigationState
1 const AppNavigator = createStackNavigator({ }) 2 const persistNavigationState = async (navState) => { 3try { 4 await AsyncStorage.setItem(‘myNavigator‘, JSON.stringigy(navState)) 5 } catch (e) { 6 } 7} 8 const loadNavigationState = async() => { 9 const jsonString = await AsynStorage.getItem(‘myNavigator‘) 10return JSON.parse(jsonString) 11} 12 const App = () => <AppContainer 13 persistNavigationState={persistNavigationState} 14 loadNavigationState={loadNavigationState} 15 />
此功能在开发模式下特别有用。你可以使用以下方法,有选择地启用它:
1 const AppContainer = createStackNavigator({ }) 2function getPersistenceFunctions () { 3return __DEV__ ? { 4 persistNavigationState, 5 loadNavigationState 6 } : undefined 7} 8 const App = () => <AppContainer {...getPersistenceFunctions()} />
由于状态是异步加载的,你可以在 AppContainer 中使用属性 renderLoadingExperimental 渲染一个空页面
自定义Android返回键行为
默认情况下,当用户按下Android 物理返回键时,reat-navigation会返回到上一个页面,如果没有可返回的页面,则退出应用。
自定义行为需要使用 react-native 的 BackHandler 这个API
1 import { BackHander } from ‘react-native‘; 2constructor() { 3this._didFocusSubscription = props.navigation.addListener( 4 ‘didFocus‘, 5 payload => BackHandler.addEventListener( 6 ‘hardeareBackPress‘, 7this.onBackButtonPressAndroid, // 返回 true 则表示我们已经处理了该事件,并且react-navigation 的事件监听器不会被调用,因此不会销毁当前页。 返回false会该方法继续执行 - react-navigation 的事件监听器将销毁当前页面。 8 ) 9 ) 10} 11componentDidMount() { 12this._willBlurSubscription = this.props.navigation.addListener( 13 ‘willBlur‘, 14 payload => 15 BackHandler.removeEventListener( 16 ‘hardwareBackPress‘, 17this.onBackButtonPressAndroid 18 ) 19 ); 20} 21 componentWillUnmount() { 22this._didFocusSubscription && this._didFocusSubscription.remove(); 23this._willBlurSubscription && this._willBlurSubscription.remove(); 24 }
参考:https://reactnavigation.org/
原文:https://www.cnblogs.com/ppJuan/p/12207335.html
内容总结
以上是互联网集市为您收集整理的React Navigation 学习全部内容,希望文章能够帮你解决React Navigation 学习所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。