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

一直没有找到有关于 react-navigation 处理app各种不同状态需要默认不同首页的例子,于是只能自己写了。
整个思路大概是这样的: 默认设置一个空页面为root页,根据需求rest至其他页面。
以下完整代码已放在github
实现效果图
react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题
文章图片
ios效果 react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题
文章图片
ios效果 react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题
文章图片
安卓效果 路由设置
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.appconst index = state.nav.index const routeName = state.nav.routes[index].routeNameconst 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 返回键处理
【react-navigation使用redux-saga等处理各种跳转、清除堆栈、返回不同页面的问题】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 }) }

    推荐阅读