react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题

一直没有找到有关于 react-navigation 处理app各种不同状态需要默认不同首页的例子,于是只能自己写了。

整个思路大概是这样的: 默认设置一个空页面为root页,根据需求rest至其他页面。

以下完整代码已放在github

实现效果图

ios效果
ios效果
安卓效果

路由设置

AppNavigation.js

// 用户token有效时默认
export const INITIAL_AUTHEN_ROUTE_NAME = 'Tab'
// 未登录时默认
export const INITIAL_UNAUTHEN_ROUTE_NAME = 'SignIn'
// 引导页首页
export const APPINTRO_ROUTE_NAME = 'AppIntro'
// 其他情况下的首页
...

// 登陆后的路由
const AUTHEN_ROUTES = {
  [INITIAL_AUTHEN_ROUTE_NAME]: { screen: TabNavigation },
  Jump1: { screen: Jump1 },
  Jump2: { screen: Jump2 }
}

export function isAuthenRouteName (routeName) {
  return !!AUTHEN_ROUTES[routeName]
}

// 无需登陆的路由
const UNAUTHEN_ROUTES = {
  SignIn: { screen: SignIn },
  Register: { screen: Register }
}

export function isUnauthenRouteName (routeName) {
  return !!UNAUTHEN_ROUTES[routeName]
}

// 其他特殊情况的路由
const GLOBAL_SCREEN = {
  AppIntro: { screen: AppIntro }
}

// 整个App路由整合
export const AppNavigation = StackNavigator({
  Launcher: { screen: Launcher },
  ...AUTHEN_ROUTES,
  ...UNAUTHEN_ROUTES,
  ...GLOBAL_SCREEN
}, {
  initialRouteName: 'Launcher',
  gesturesEnabled: true,
  headerMode: 'none',
  transitionConfig: () => ({
    screenInterpolator: CardStackStyleInterpolator.forHorizontal
  })
})

处理安卓返回多次问题

AppNavigation.js

const defaultGetStateForAction = AppNavigation.router.getStateForAction
AppNavigation.router.getStateForAction = (action, state) => {
  const { type, routeName } = action

  // jump twice
  if (state &&
    type === NavigationActions.NAVIGATE &&
    routeName === state.routes[state.routes.length - 1].routeName
  ) return null
  
  ...

  return defaultGetStateForAction(action, state)
}

处理返回至某个堆栈

AppNavigation.js

const defaultGetStateForAction = AppNavigation.router.getStateForAction
AppNavigation.router.getStateForAction = (action, state) => {
  const { type, routeName } = action

  ...

  // back to one stack
  if (state && type === NavigationActions.BACK) {
    const backRoute = state.routes.find(route => route.routeName === action.key)
    if (backRoute) {
      const backRouteIndex = state.routes.indexOf(backRoute)
      const route = {
        ...state,
        routes: state.routes.slice(0, backRouteIndex + 1),
        index: backRouteIndex
      }
      return route
    }
  }

  return defaultGetStateForAction(action, state)
}

根据不同状态设置不同根路径

NavigationSagas.js

import { put, select } from 'redux-saga/effects'
import { NavigationActions } from 'react-navigation'

import {
  isAuthenRouteName,
  isUnauthenRouteName,
  INITIAL_AUTHEN_ROUTE_NAME,
  INITIAL_UNAUTHEN_ROUTE_NAME,
  APPINTRO_ROUTE_NAME
} from '../Navigation/AppNavigation'

export function * redirectFlow () {
  const state = yield select()

  const authenticated = state.user.isLoggedIn
  const app = state.app

  const index = state.nav.index
  const routeName = state.nav.routes[index].routeName

  const redirectRoute = (name, childRouteName) => NavigationActions.reset({
    index: 0,
    actions: [
      NavigationActions.navigate({ routeName: name })
    ]
  })
  
  // 需要引导页时
  if (!app.hasReadAppintro) {
    yield put(redirectRoute(APPINTRO_ROUTE_NAME))
  }
  ...
  else {
    // 用户登陆时
    if (authenticated && !isAuthenRouteName(routeName)) {
      yield put(redirectRoute(INITIAL_AUTHEN_ROUTE_NAME))
      
    // 用户未登录时
    } else if (!authenticated && !isUnauthenRouteName(routeName)) {
      yield put(redirectRoute(INITIAL_UNAUTHEN_ROUTE_NAME))
    }
  }
  // 利用启动页遮盖跳转过程
  // SplashScreen.hide()
}

跳转后清除某些堆栈

NavigationSagas.js

// routeName 为要跳转的栈
export function * resetFlow ({ routeName, stackName }) {
  const state = yield select()

  let routes = []

  // 清除 堆栈中 stackName 到 routeName 之间的堆栈
  if (stackName) {
    for (let i = 0; i < state.nav.routes.length; i++) {
      routes.push(state.nav.routes[i])
      if (state.nav.routes[i].routeName === stackName) break
    }
  } else {
    routes = state.nav.routes
  }

  let actions = routes.map((item, key) =>
    key === (routes.length - 1)
    ? NavigationActions.navigate({ routeName: routeName })
    : NavigationActions.navigate({ routeName: item.routeName })
  )

  const redirectRoute = NavigationActions.reset({
    index: actions.length - 1,
    actions: actions
  })

  yield put(redirectRoute)
}

android 返回键处理

RootContainer.js

_BackHandler = () => {
  BackHandler.addEventListener('hardwareBackPress', () => {
    const { routes } = this.props.nav
    if (routes.length > 1) {
      this.props.goBack({ key: routes[routes.length - 1]['key'] })
      return true
    }
    // if in root, < 2s
    if (this.lastBackPressed && (this.lastBackPressed + 2000 >= Date.now())) {
      BackHandler.exitApp()
      return true
    }
    this.lastBackPressed = Date.now()
    Toast.show('again quit')
    return true
  })
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • react-navigation导航组件使用详解 注意了,如果有小伙伴们发现运行作者提供的react-naviga...
    光强_上海阅读 23,427评论 38 103
  • 青丝白马 魂断,天涯 昨日曾经最美 待我,长发及腰 几人陪我刀剑神域 蹉跎自误 如何,捡拾当年明月 一梦华胥 谁是...
    红学砖家阅读 212评论 0 6
  • 上世纪八十年代。 二丫头,一根晒衣绳吊成了鬼的人 二丫头长的标致、好看,这是全村人公认的,也是村上人跟她其他七个兄...
    心花朵朵阅读 569评论 0 0
  • 时下流行花鸟虫鱼的饲养,我一样儿不爱。 主要是本人具有懒的优点。 因照顾不周而导致它们萎靡,甚至死亡,于心戚戚焉。...
    小小卷耳阅读 294评论 2 3