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.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
})
}
推荐阅读
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- iOS中的Block
- Linux下面如何查看tomcat已经使用多少线程
- 使用composer自动加载类文件
- android|android studio中ndk的使用
- 使用协程爬取网页,计算网页数据大小