• React-Navigation redux集成


    对于这个程序的页面导航结构,我是这样看的。首先,一个标签栏本身就是自己的导航器,而上面每个标签同样是自己的导航器。在这个例子里,我要用带有三个标签的标签栏,所以一共有四个导航器,每个导航器都有自己的还原器(reducer)和状态。

    我又把代码分成几个“功能”,所以整个结构看起来是这样的:

    /app
      /tabBar
        /views
          TabBarNavigation.js
        navigationConfiguration.js
      /tabOne
        /views
          TabOneNavigation.js
          TabOneScreenOne.js
          TabOneScreenTwo.js
        navigationConfigutation.js
      /tabTwo
        /views
          TabTwoNavigation.js
          TabTwoScreenOne.js
          TabTwoScreenTwo.js
        navigationConfiguration.js

      /tabThree
        /views
          TabThreeNavigation.js
          TabThreeScreenOne.js
          TabThreeScreenTwo.js
        navigationConfiguration.js

    store.js

    标签栏配置

    先从标签栏开始,标签栏是程序的入口处,而且是最顶端的导航器。根据说明文档,要构建一个标签栏需要调用一个函数叫TabNavigator(RouteConfigs, TabNavigatorConfig)。这个函数有两个参数:RouteConfigs和TabNavigatorConfig,路线配置参数(RouteConfigs)就是单个的标签,也代表了单个的导航器。也就是说,这里每个单独的标签导航器都是我们给标签栏设定的导航路线。

    导航路线以键/值成对定义,比如ScreenName: { screen: ScreenName },所以路线配置参数就是一列可能要导航的路线。在这个例子里,导航路线是可能要转到的标签。

    标签导航设置(TabNavigatorConfig)参数是程序接口提供的选项,可以用来自定义标签栏。这个参数只是由几对键: 值结构组成的JS对象而已。其中最重要的一对是标签栏选项(tabBarOptions),靠这个选项可以设定标签激活时与不激活时的颜色。

    我整个导航配置都写在一个独立的JS文件里,比较简洁,可以在其它地方引入和调用,看起来像这样:

    //'use strict'
    import { TabNavigator } from 'react-navigation'
    // Tab-Navigators
    import TabOneNavigation from '../tabOne/views/TabOneNavigation'
    import TabTwoNavigation from '../tabTwo/views/TabTwoNavigation'
    import TabThreeNavigation from '../tabThree/views/TabThreeNavigation'
    const routeConfiguration = {
      TabOneNavigation: { screen: TabOneNavigation },
      TabTwoNavigation: { screen: TabTwoNavigation },
      TabThreeNavigation: { screen: TabThreeNavigation },
    }
    const tabBarConfiguration = {
      //...other configs
    tabBarOptions:{
        // tint color is passed to text and icons (if enabled) on the tab bar
        activeTintColor: 'white',
        inactiveTintColor: 'blue',
    // background color is for the tab component
        activeBackgroundColor: 'blue',
        inactiveBackgroundColor: 'white',
      }
    }
    export const TabBar = TabNavigator(routeConfiguration,tabBarConfiguration)

    完成标签栏配置

    标签栏构建好之后,还没有成型,不能进行实际渲染。我们还要设置好每个标签导航器,使它们也能正确地渲染屏幕显示。这些导航器我们称为栈导航器(StackNavigators)。

    栈导航器配置

    根据说明文档,要构建一个栈导航器,需要调用一个和TabNavigator很类似的函数叫StackNavigator(RouteConfigs, StackNavigatorConfig),同样有两个参数,只是这个函数的参数里配置更多。参看说明文档来获取更多信息。

    简单地配置设定一下,和标签栏配置差不多:

    //'use strict'
    import { StackNavigator } from 'react-navigation'
    // Screens
    import TabOneScreenOne from './views/TabOneScreenOne'
    import TabOneScreenTwo from './views/TabOneScreenTwo'
    
    const routeConfiguration = {
      TabOneScreenOne: { screen: TabOneScreenOne },
      TabOneScreenTwo: { screen: TabOneScreenTwo },
    }
    // going to disable the header for now
    const stackNavigatorConfiguration = {
      headerMode: 'none',
      initialRouteName: 'TabOneScreenOne'
    }
    export const NavigatorTabOne = StackNavigator(routeConfiguration,stackNavigatorConfiguration)
    //只要改个名,就把三个标签都设置好了。创建一个简单的屏幕组件来渲染
    import React from 'react'
    import { View, Text } from 'react-native'
    export default class TabOneScreenOne extends React.Component {
    render(){
        return(
          <View style={{
            flex:1,
            backgroundColor:'red',
            alignItems:'center', 
            justifyContent:'center'
          }}>
            <Text>{ 'Tab One Screen One' }</Text>
          </View>
        )
      }
    }

    完成栈导航器配置

    是时候把所有的部分都串起来了

    配置redux-store实例

    有一个很有用的辅助函数叫getStateForAction,它和路由挂钩,并处理所有的导航逻辑。

    这个函数在Redux store实例中这样用:

    //'use strict'
    // Redux
    import { applyMiddleware, combineReducers, createStore } from 'redux'
    import logger from 'redux-logger'
    // Navigation
    import { NavigatorTabOne } from './tabOne/navigationConfiguration'
    import { NavigatorTabTwo } from './tabTwo/navigationConfiguration'
    import { NavigatorTabThree } from './tabThree/navigationConfiguration'
    import { TabBar } from './tabBar/navigationConfiguration'
    
    // Middleware
    const middleware = () => {
      return applyMiddleware(logger())
    }
    
    export default createStore(
      combineReducers({
        tabBar: (state,action) => TabBar.router.getStateForAction(action,state),
    tabOne: (state,action) => NavigatorTabOne.router.getStateForAction(action,state),
    tabTwo: (state,action) => NavigatorTabTwo.router.getStateForAction(action,state),
    tabThree: (state,action) => NavigatorTabThree.router.getStateForAction(action,state),
      }),
      middleware(),
    )
    // React
    import React from 'react'
    import { AppRegistry } from 'react-native'
    
    // Redux
    import { Provider } from 'react-redux'
    import store from './app/store'
    
    // Navigation
    import TabBarNavigation from './app/tabBar/views/TabBarNavigation'
    
    class SampleNavigation extends React.Component {
      render(){
        return(
          <Provider store={store}>
            <TabBarNavigation />
          </Provider>
        )
      }
    }
    AppRegistry.registerComponent('SampleNavigation', () => SampleNavigation)

    与标签栏挂钩

    还记得本文一开始,我们创建了一些参数,然后传入一个函数来创建标签栏吗?要将导航控制权从react-navigation库转移到Redux State实例中去,我们需要给创建出来的标签栏提供导航状态,再用react-navigation库拥有的辅助函数来分派出去。为标签栏建立的文件像这样:

    // React
    import React from 'react'
    // Navigation
    import { addNavigationHelpers } from 'react-navigation'
    import { TabBar } from '../navigationConfiguration'
    //Redux
    import { connect } from 'react-redux'
    const mapStateToProps = (state) => {
     return {
      navigationState: state.tabBar,
      }
    }
    class TabBarNavigation extends React.Component {
    render(){
        const { dispatch, navigationState } = this.props
        return (
          <TabBar
            navigation={
              addNavigationHelpers({
                dispatch: dispatch,
                state: navigationState,
              })
            }
          />
        )
      }
    }
    export default connect(mapStateToProps)(TabBarNavigation)

    将栈导航器与每个独立的标签挂钩

    基本上和标签栏一样的方法。

    import React from 'react'
    // Navigation
    import { addNavigationHelpers } from 'react-navigation'
    import { NavigatorTabOne } from '../navigationConfiguration'
    // Redux
    import { connect } from 'react-redux'
    // Icon
    import Icon from 'react-native-vector-icons/FontAwesome'
    const mapStateToProps = (state) => {
     return {
      navigationState: state.tabOne
      }
    }
    class TabOneNavigation extends React.Component {
    render(){
        const { navigationState, dispatch } = this.props
        return (
          <NavigatorTabOne
            navigation={
              addNavigationHelpers({
                dispatch: dispatch,
                state: navigationState
              })
            }
          />
        )
      }
    }
    export default connect(mapStateToProps)(TabOneNavigation)

    这样应该能生成程序,运行程序并且在程序中导航了。但不怎么好看

    让我们去掉那些难看的文字,加些iOS系统图标吧。

    要改变标签文字,加上图标,只要把static navigationOptions声明放在各自的标签导航器里就行了。记得在标签栏配置里,我们设置了tintColors颜色,现在就可以用这些颜色了。

    第一个标签导航器:

    // React
    import React from 'react'
    // Navigation
    import { addNavigationHelpers } from 'react-navigation'
    import { NavigatorTabOne } from '../navigationConfiguration'
    // Redux
    import { connect } from 'react-redux'
    // Icon
    import Icon from 'react-native-vector-icons/FontAwesome'
    const mapStateToProps = (state) => {
     return {
      navigationState: state.tabOne
      }
    }
    class TabOneNavigation extends React.Component {
      static navigationOptions = {
        tabBarLabel: 'Tab One',
        tabBarIcon: ({ tintColor }) => <Icon size={ 20 } name={ 'cogs' } color={ tintColor }/>
    
      }
    render(){
        const { navigationState, dispatch } = this.props
        return (
          <NavigatorTabOne
            navigation={
              addNavigationHelpers({
                dispatch: dispatch,
                state: navigationState
              })
            }
          />
        )
      }
    }
    export default connect(mapStateToProps)(TabOneNavigation)

    看起来不错。

    现在我们来处理标签内部之间的导航。我要在每个标签的第一屏加一个按钮,能导航到新的路线上去。

    标签一,屏幕一:

    'use strict'
    import React from 'react'
    import { View, Text, TouchableOpacity } from 'react-native'
    export default class TabOneScreenOne extends React.Component {
      render(){
        return(
          <View style={{
            flex:1,
            backgroundColor:'red',
            alignItems:'center',
            justifyContent:'center'
          }}>
            <Text>{ 'Tab One Screen One' }</Text>
            <TouchableOpacity
              onPress={ () => this.props.navigation.navigate('TabOneScreenTwo') }
              style={{
                padding:20,
                borderRadius:20,
                backgroundColor:'yellow',
                marginTop:20
              }}>
              <Text>{'Go to next screen this tab'}</Text>
            </TouchableOpacity>
          </View>
        )
      }
    }

    标签一,屏幕二:

    use strict'
    import React from 'react'
    import { View, Text, TouchableOpacity } from 'react-native'
    export default class TabOneScreenTwo extends React.Component {
      render(){
        return(
          <View style={{
            flex:1,
            backgroundColor:'orange',
            alignItems:'center',
            justifyContent:'center'
          }}>
            <Text>{ 'Tab One Screen Two' }</Text>
            <TouchableOpacity
              onPress={ () => this.props.navigation.goBack() }
              style={{
                padding:20,
                borderRadius:20,
                backgroundColor:'purple',
                marginTop:20
              }}>
              <Text>{'Go back a screen'}</Text>
            </TouchableOpacity>
    </View>
        )
      }
    }

    现在所有的导航状态都储存在redux store实例中了。

    有了这个信息,就可以相当方便并任意地处理安卓系统回退键(AndroidBack)行为了。

    如果想让后退按钮回到某一标签的某一屏幕,只要加一个侦听器即可。

    BackHandler.addEventListener('hardwareBackPress', this.backAction )
    backAction = () => {
      // get the tabBar state.index to see what tab is focused
      // get the individual tab's index to see if it's at 0 or if there  is a screen to 'pop'
    if (you want to pop a route) {
        // get the navigation from the ref
        const { navigation } = this.navigator.props
        // pass the key of the focused route into the goBack action
         navigation.goBack(navigation.state.routes[navigation.state.index].key)
        return true
      } else {  
        return false
      }
    }
    <TabWhateverNavigator
      ref={ (ref) => this.navigator = ref }
      navigation={
        addNavigationHelpers({
          dispatch: dispatch,
          state: navigationState
         })
      }
    />

    自定义行为/还原器/路由/不管叫什么

    想不想通过屏幕上的按钮跳转至标签呢?我想的。这里有一个方法:

    getStateForAction函数放到navigationConfiguration文件里去,这样更好看些。让它拦截自定义行为或只是将同一个函数返回。

    像这样tabBar => navigationConfiguration,我这个例子目的就达到了

    export const tabBarReducer = (state, action) => {
      if (action.type === 'JUMP_TO_TAB') {
        return { ...state, ...action.payload }
      } else {
        return TabBar.router.getStateForAction(action,state)
      }
    }

    标签三的屏幕上有一个按钮

    <TouchableOpacity
              onPress={ 
                () => this.props.navigation.dispatch({ type:'JUMP_TO_TAB', payload:{index:0} }) 
              }
              style={{
                padding:20,
                borderRadius:20,
                backgroundColor:'deeppink',
                marginTop:20
              }}>
              <Text>{'jump to tab one'}</Text>
            </TouchableOpacity>

    还有新的store实例

    //...stuff and things
    import { TabBar, tabBarReducer } from './tabBar/navigationConfiguration'
    // more things
    export default createStore(
      combineReducers({
    
        //...other stuff and more things
        tabBar: tabBarReducer, 
        }),
      middleware(),
    )

    原文:http://www.zcfy.cc/article/react-navigation-complete-redux-state-management-tab-bar-and-multiple-navigators-4449.html

     

     

     
  • 相关阅读:
    Re: 求助:5道算法题
    AutoComplete的字典建立和单词查找算法实现
    求教大牛!关于后缀树
    Qt OpenGL教程
    调试宏
    if结合errorlevel使用:判断一个DOS命令执行成功与否
    写给自己,关于对纯技术的追求,以及为了金钱与前途的技术追求
    <转>我对菜鸟成长的看法
    看完电影有感。。。。。
    <转>标准C++的类型转换符:static_cast、dynamic_cast、reinterpret_cast、和const_cast
  • 原文地址:https://www.cnblogs.com/chenzxl/p/7993372.html
Copyright © 2020-2023  润新知