React-navigation 路由任意跳转总结

前言

使用ReactNative很长时间了,官方版本更新的太快了,最近才把公司的项目升级到最新,其中导航,官方已经遗弃了Navigator,推荐使用React-Navigation.基础的东西就不介绍了,可以去官网看看。

介绍

本文主要解决这样一个场景,假如有4个页面,A,B,C,D.我们跳转的顺序是A->B->C->D,现在想从D回到B,官方没有提供直接的接口让我们操作。结合前人的经验,本人亲自验证后,做出此总结(废话有点多 - -!)。

正题
  1. 使用NavigationService
    这个是官方介绍的一种抽取一个公共类来操作跳转方法,该方法用于解放双手,妈妈再也不用担心我不停的写this.props.navigation了,本例也采用这种方式来实现我们的需求。具体代码如下:
import {NavigationActions} from 'react-navigation';

 let _navigator;
 let _routers;
 let _navigation;
 
 /**
  * 设置顶层路由导航
  * @param navigatorRef
  */
 function setTopLevelNavigator(navigatorRef) {
     _navigator = navigatorRef;
 }
 
 /**
  * 设置当前路由栈和导航对象
  * @param routers
  * @param navigation
  */
 function setRouters(routers, navigation) {
     _routers = routers;
     _navigation = navigation;
 }
 
 /**
  * 跳转到指定页面
  * @param routeName
  * @param params
  */
 function navigate(routeName, params) {
     _navigator.dispatch(
         NavigationActions.navigate({
             type: NavigationActions.NAVIGATE,
             routeName,
             params,
         })
     );
 }
 
 /**
  * 返回到顶层
  */
 function popToTop() {
     _navigator.dispatch(NavigationActions.popToTop())
 }
 
 /**
  * 返回第n个页面
  * @param n
  */
 function popToN(n) {
     if (n <= 0) {
         return;
     }
     let len = _routers.length;
     if (len < n || n === len - 1) {
         this.popToTop();
         return;
     }
     _navigation.goBack(_routers[len - n].key);
 
 }
 
 /**
  * 返回
  */
 function goBack() {
     _navigator.dispatch(NavigationActions.back({type: NavigationActions.BACK}));
 }
 
 /**
  * 返回到任意页面
  * @param routeName
  */
 function popToRouter(routeName) {
     if (!routeName) {
         this.goBack();
         return;
     }
     let len = _routers.length;
     for (let i = 0; i < len - 1; i++) {
         let route = _routers[i];
         if (routeName === route.routeName && i !== len - 1) {
             _navigation.goBack(_routers[i + 1].key);
             return;
         }
     }
 }
 
 export default {
     setTopLevelNavigator,
     setRouters,
     navigate,
     popToRouter,
     goBack,
     popToTop
 };
复制代码
  1. 在入口出将顶层导航设置到公共方法中
    这里需要在配置React-navigation顶层导航的地方,将顶层导航设置到公共导航类中,代码如下:
import React, {Component} from 'react'
 import NavigationService from './NavigationService'
 import { StackNavigator} from 'react-navigation'
 import Page1 from "../page/Page1";
 import Page2 from "../page/Page2";
 import Page3 from "../page/Page3";
 import Page4 from "../page/Page4";
 import Page5 from "../page/Page5";
 
 const screens ={
     Page1:{
         screen:Page1,
     },
     Page2:{
         screen:Page2,
         navigationOptions:{
             title:'Page2'
         }
     },
     Page3:{
         screen:Page3,
         navigationOptions:{
             title:'Page3'
         }
     },
     Page4:{
         screen:Page4,
         navigationOptions:{
             title:'Page4'
         }
     },
     Page5:{
         screen:Page5,
         navigationOptions:{
             title:'Page5'
         }
     }
 }
 
 const Nav = new StackNavigator({
     ...screens
 })
 
 class App extends Component {

     render() {
         return (
             <Nav
                 ref={navigatorRef => {
                     NavigationService.setTopLevelNavigator(navigatorRef);//设置顶层导航
                 }}
             />
        )
     }
 }
 export default App;
复制代码
  1. 使用NavigationService
    简单的跳转:
//对应this.props.navigation.navigate(routeName)
 NavigationService.navigate('Page2');
 
 //对应this.props.navigation.goBack();
 NavigationService.goBack();
 
 //返回到路由栈顶层
 NavigationService.popToTop();
 
 //返回到第n层页面
 NavigationService.popToN(n);
 
 //返回到指定页面(routeName页面必须在当前路由栈中)
 NavigationService.popToRouter(routeName)
复制代码

上面的前三个方法可以直接用,后面两个是用于返回任意页面,需要在路由栈的顶层页面配置一下,代码如下:

static navigationOptions = {
     header:({navigation}) =>{
         let {state:{routes}} = navigation;
         NavigationService.setRouters(routes, navigation);
         return null;
     }
 };
复制代码

上面代码大意是,拿到当前路由的路由栈(一个包含当前路由信息的数组),有路由数组了,我们就可以为所欲为之为所欲为了。

  1. 解放双手之传参
    使用过React-navigation的都知道,如果要接受上个页面的传来的参数,就需要写:this.props.navigation.params.***.如果项目中很多页面需要传递参数,那这代码就恶心至极。如果是升级之前的代码,那需要全局替换this.props
    使用很简单只需要在接受参数的页面类的头部加上一句注解
import { withMappedNavigationProps } from 'react-navigation-props-mapper'
 
 @withMappedNavigationProps()
 export class SomeScreen extends Component {
复制代码

如果你使用了mobx的observer注解,不好意思,这里会有冲突,解决办法就是把@observer放下面。