美文网首页React Native学习
react-navigation使用redux-saga等处理各

react-navigation使用redux-saga等处理各

作者: 名字还是土一点好 | 来源:发表于2018-01-21 14:26 被阅读410次

    一直没有找到有关于 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
      })
    }
    

    相关文章

      网友评论

        本文标题:react-navigation使用redux-saga等处理各

        本文链接:https://www.haomeiwen.com/subject/hwnfaxtx.html