react-navigation使用介绍及UI组件外实现统一跳转

5,543 阅读7分钟

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端运行效果如下:

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,可以直接扫码查看效果,赶紧安装吧~