react-navigation v6 中文极速版

前言

react-navigation虽然一直在用,但始终没有将官网(英文版)给过一遍,最近要搭建一个新项目,对于导航嵌套有一定的要求,就借此机会将文档详细过了一下。阅读过程中发现很多想要的功能人家本身就支持,因为之前没有认真看文档,自己又造了一遍轮子而且还留下一些坑。借此机会将所有文档给梳理一下

1. 名词解释

  1. navigator
    导航器,比如:StackNavigator/TabNavigator/DrawerNavigator
  2. screen
    在导航器中配置的真正显示在屏幕上的组件,只有这类组件的props上才有navigation对象
  3. navigation
    导航对象,我们通过他进行屏幕的跳转
  4. route
    路由对象,包含着该页面的key、name及路由参数
  5. state
    路由栈

2. 各种导航API

主要分如下几类:

  1. DrawerActionHelpers
    在这里插入图片描述

  2. TabActionHelpers
    在这里插入图片描述

  3. StackActionHelpers
    在这里插入图片描述

  4. NavigationHelpersCommon
    在这里插入图片描述

  5. EventConsumer
    在这里插入图片描述

  6. NavigationProp在这里插入图片描述

下面说几个我感觉需要需要记录的

  1. navigate、push
    navigation.navigate('RouteName'),如果指定路由在路由栈中存在,会回到该页面,否则会push到一个新页面;navigation.push('RouteName'),无论指定路由是否在路由栈中,都会新建一个路由页面并跳转过去。

    疑问: A push B,B push C,C push D,D navigate A后,路由栈中还会存在BCD么

    不会存在,经测试,navigate到哪个已存在的页面,该页面之后的路由都会被清空。下面附上两个case的结果
    D navigate A后,路由栈中只剩A;D navigate B后,路由栈中只剩A、B

  2. setParams
    上个页面传过来的路由参数要做修改,直接通过setParams更改即可,不用再次新建一个state处理

    疑问:setParams会触发render么

    会,我将parmas的属性做为文本内容,点击按钮setParams后,文本内容更新

  3. setOptions
    可以使用该API直接更新标题,另外当导航想要配置自定义的button组件时,也可以通过setOptions配置

  4. getParent
    获取父导航,比如A页面是直接嵌套在Stack导航下,Stack是嵌套在Drawer下,在A页面是无法直接使用navigation.openDrawer()打开导航,需要先获取父导航navigation.getParent().openDrawer()

  5. dispatch
    导航操作可以通过dispatch分发对应的action实现,比如:navigation.dispatch(DrawerActions.openDrawer)

3. 生命周期

官方原文

  1. useFocusEffect
    页面显示时调用,传递的回调应该包裹在 React.useCallback 中,以避免过于频繁地调用

    import { useFocusEffect } from '@react-navigation/native';
    
    function Profile() {
      useFocusEffect(
        React.useCallback(() => {
          // Do something when the screen is focused
    
          return () => {
            // Do something when the screen is unfocused
            // Useful for cleanup functions
          };
        }, [])
      );
    
      return <ProfileContent />;
    }
    
  2. useIsFocused,当前页面是否处于焦点状态
    如果您使用的是选项卡或抽屉式导航器,因为导航器中的所有屏幕可能会同时渲染并保持渲染 - 这意味着StatusBar您设置的最后一个配置将被使用(可能在最后一个选项卡上您的标签导航器,而不是用户所看到的。为了解决这个问题,我们必须让状态栏组件知道屏幕焦点,并仅在屏幕获得焦点时渲染它。我们可以通过使用useIsFocused钩子并创建一个包装器组件来实现这一点:

    import * as React from 'react';
    import { StatusBar } from 'react-native';
    import { useIsFocused } from '@react-navigation/native';
    
    function FocusAwareStatusBar(props) {
      const isFocused = useIsFocused();
    
      return isFocused ? <StatusBar {...props} /> : null;
    }
    
  3. 疑问:在该页面的子组件是否可以使用这两个API
    可以,将这两个API放到子组件里,可以得到正确的结果

  4. 疑问:有useBlurEffet么
    找了,没有,如果想要使用,使用使用如下订阅的方式

    const unsubscribe = navigation.addListener('blur', () => {
      // Screen was focused
      // Do something
    });
    

    另外官方提供的页面生命周期只有focusblur

4. 身份验证

官方原文

这里介绍的这种方案更适用于没有访客模式的那种App,在此我学到了两个小知识点:

  1. 路由注册是可以动态切换的,说不定以后碰到啥奇怪的业务场景就用上了
  2. 可以将一些配置相同的路由放到一个路由group中,在group上统一配置

通过这种案例,我了解到

5. 安全区域

官方原文

  1. 内部使用的是react-native-safe-area-context来处理的安全区域,其他的方式要么有问题,要么已经过时
  2. 可以通过SafeAreaViewedges属性控制哪边自动填充被盖住的区域,比如:当前页面没有导航,我又不想让安全区域顶到到屏幕的最上方,就可以将该属性设置为['top']
  3. 使用useSafeAreaInsets钩子能够得到安全区域的偏移量,然后做你想做的事情

6. 状态栏

官方原文

之所以要判断当前页面是否是焦点,是因为若项目中有选项卡或抽屉,可能会同时渲染,造成一些莫名的异常

import * as React from 'react';
import { StatusBar } from 'react-native';
import { useIsFocused } from '@react-navigation/native';

function FocusAwareStatusBar(props) {
  const isFocused = useIsFocused();

  return isFocused ? <StatusBar {...props} /> : null;
}

7. 多个抽屉

官方原文

在抽屉路由中,控制抽屉方向的drawerPosition属性不可动态更改,因此若项目中既有左抽屉又有右抽屉,就需要嵌套两个抽屉实现,在这里也用到了一个getParent的API来获取两个抽屉路由的导航实例进而控制在哪边显示抽屉

8. 嵌套导航的options该如何配置

官方原文

首先摆上官方加粗的一句话:

不管是单个导航还是嵌套导航,修改父导航的options只能在该导航下的screen component中通过navigation.setOptions进行修改,

我理解的是:A嵌套B,B嵌套C,无法在C中修改A的options

9. 返回上一级时的二次确认

官方原文

可以用两种方式来实现:

  1. BackHandler监听
  2. beforeRemove事件,其中提到的preventDefault在iOS上无效

在没有beforeRemove之前,要实现这种效果基本就是如下几种方式:

  1. 重新header的返回按钮
  2. 禁用滑动返回手势
  3. 重写Android的系统返回事件

这个新增的API除了代码量更少外,还有以下几个特色:

  1. 他不跟任何的特定按钮绑定,自定义的返回按钮也可触发
  2. 他不跟任何的特定action绑定,任何从state中移除route的操作都可触发,比如:pop/reset/swipe 等
  3. 支持嵌套导航,比如:由父路由发送的action导致的移除route也会触发该监听
  4. 用户仍然可以滑动返回,但如果监听事件里做了prevented处理,该侧滑操作将会被取消
  5. 在监听事件里可以通过navigation.dispatch(e.data.action) 继续最初确定的路由回退操作

虽然很强大,但也有一些限制:

  1. 当用户由于不受导航状态控制的操作而退出屏幕时,不会触发该监听,比如:

    • 退出退出App、退出浏览器
    • 由于预期或非预期的原因,造成screen被卸载
  2. @react-navigation/native-stack中,如下两个操作该监听会失效:

    1. 侧滑返回
    2. 点击自带的返回按钮

    解决方案也简单,对于前者只能禁用侧滑返回,对于后者自定义返回按钮就行

10. 获取到navigation实例的三种方式

hook获取
ref获取

  1. props中取
  2. useNavigation中取(本质上是通过context获取到了screen component上的navigation)
  3. 获取createNavigationContainerRef

前两者都是在组件内获取在组件内使用,但当我要在非组件内实现路由跳转(比如:redux中),就要使用第三种方式,这种方式跟前两者相比有如下缺陷:
4. 针对screen component的一些特定API,ref不支持,比如:setOption/push
5. 路由跳转的灵敏度和用户体验有所降低

因此对于第三种方式,应该尽可能的避免使用,除非迫不得已

11. Deep linking与react-navigation的融合

Linking的主要作用是通过访问指定连接来启动App,在项目中,我们可以获取链接上的参数,通过参数来判定跳转到哪个页面。导航库官方推荐使用官方提供的融合方案,强烈不建议自行手动将两者结合,主要是因为官方的方案针对一些边缘case都做了处理,若自行手动处理会比较麻烦。官方也详细介绍了基础配置及各种项目下如何测试,具体看deep-linking

基础介绍和基础配置搞完了,官方也专门提供了一个文档说明里面的各种case如何配置,详细看configuring-links,我下面讲我认为比较重点的内容标记一下:

  1. config中配置路由和path的映射关系时,嵌套关系要和实际路由嵌套一致
  2. 配置path的方式有多种,不同场景对应的path有些差异,大家根据实际需求做选择
  3. config中,可通过parse对参数进行自定义处理,还提到一个stringify参数,没有搞明白他是要干嘛,经测试他也没有执行
  4. 若在config中不配置initialRouteName,通过Link冷启动App,无法返回上一级,另外在此场景下,url中无法给初始路由设置参数,返回的页面必须无参数据,或者通过screeninitialParams给设置初始参数
  5. 官方本质上是将url转化成state,然后使用dispatch做分发实现的路由跳转,为了为了增强扩展性,官方将getStateFromPathgetPathFromState开放给开发者,让开发者能够做更高阶的事情

在web上的一些注意点:

  1. 配置link前在web上的跳转不会改变url,配置link后会将路径和参数拼到url后
    1. 路径默认是按照路由嵌套的顺序展示(若嵌套过深,路径过长,官方提供有简化方案)
    2. 参数默认是按照query的格式拼接,若在path中有指定拼接方式,跳转时会按照指定格式处理

12. 对web的支持

原文

对web的支持还是比较友好的,无论从文档上还是从实际使用上,都还没有发现有啥需要特别处理的。

13. 路由跳转监听

原文

可以在这里做些页面的埋点操作

14. 主题切换及自定义

原文

还挺完善的

15. state持久化

我们在调试深层级页面时,有时一旦reload,还得再次一层一层点进去,这里做的事情就是实时将路由栈在本地维护一份,reload后从本地取出,恢复路由栈

16. ts类型

本质上主要解决两个问题:

  1. 路径和对应的参数提示
  2. 各种navigator上的API提示

官方针对导航嵌套的场景也帮助我们做了示例,若这里配置齐全,在配置Linking时会比较方便

17. 其他的一些API

  1. getFocusedRouteNameFromRoute
    获取到某个嵌套导航器下获取到焦点的路由名称,使用场景:要求tab的标题跟其下页面的路由名称有关

18. 导航嵌套

上诉都看完后,或多或少对导航嵌套这一块应该都不陌生了。接下来我提供几种嵌套导航Demo,并列出相关特性,大家可根据业务情况做抉择,或者扩展出更适合自己业务的导航嵌套模式。

不知不觉,本篇幅已快七千,又因为这块整体比较独立,我就单开一篇文章,react-navigation的各种导航嵌套优劣势

19. API介绍

在上面的介绍中,已经接触了一些API,但始终缺乏对这些API的系统化认识,我再过一遍的目的,主要想让自己做下查漏补缺,该内容整体比较独立,也单开一个文章,react-navigation的API梳理

20. 自定义导航

官方原文
我之所以提到,是想说明该库支持自定义导航,用到的时候再详细研究吧

21. 可替换的导航库

官方原文

  1. react-native-router-flux: 基于react-navigation,但提供了一些不同的API
  2. react-native-navigation:在iOS和Android上使用底层本地API,类似于createNativeStackNavigator。这是React Navigation的一个流行替代方案,如果您试图将React Native集成到现有的大型本地应用程序中,它可能更适合您。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值