React-navigation 路由任意跳轉總結

菜鳥座的小菜鳥發表於2018-04-30

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
     };
    複製程式碼
  2. 在入口出將頂層導航設定到公共方法中

    這裡需要在配置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;
    複製程式碼
  3. 使用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;
         }
     };
    複製程式碼

    上面程式碼大意是,拿到當前路由的路由棧(一個包含當前路由資訊的陣列),有路由陣列了,我們就可以為所欲為之為所欲為了。

  4. 解放雙手之傳參

    使用過React-navigation的都知道,如果要接受上個頁面的傳來的引數,就需要寫:this.props.navigation.params.***.如果專案中很多頁面需要傳遞引數,那這程式碼就噁心至極。如果是升級之前的程式碼,那需要全域性替換this.props,現在有個大神替我們解決了這個麻煩,原始碼地址react-navigation-props-mapper

    使用很簡單隻需要在接受引數的頁面類的頭部加上一句註解(當然使用之前需要引入大神的庫):

     import { withMappedNavigationProps } from 'react-navigation-props-mapper'
     
     @withMappedNavigationProps()
     export class SomeScreen extends Component {
    複製程式碼

    如果你使用了mobx的observer註解,不好意思,這裡會有衝突,解決辦法就是把@observer放下面。

    若有需要看本例原始碼,請移步這裡,如果對您有用,希望star一下,萬分感謝,如果有說的不對的地方,還望各位指正,拜謝。

相關文章