如何在React Native/Redux中使用推送路由为NavigationStateUtils创建唯一键?

Jo *_* Ko 8 javascript ios reactjs react-native redux

目前,我使用React Native/Redux使用NavigationStateUtils设置了Push和Pop.但是当一个触发Push动作的按钮被多次按下时,我得到错误:should not push * route with duplicated key和*表示route.keythis.props.navKey.

可能是错误的原因是什么?我该如何使用NavigationStateUtils?为每条路线创建一个唯一的密钥?

这是我的设置 - Redux:

function mapStateToProps(state) {
  return {
    navigation: state.navReducer,
  }
}

export default connect(
  mapStateToProps,
  {
    pushRoute: (route) => push(route),
    popRoute: () => pop(),
  }
)(NavigationRoot)
Run Code Online (Sandbox Code Playgroud)

我的减速机(navReducer.js):

const initialState = {
  index: 0,
  key: 'root',
  routes: [{
   key: 'login',
   title: 'Login',
   component: Login,
   direction: 'horizontal',
  }]
}

function navigationState (state = initialState, action) {
  switch(action.type) {
    case PUSH_ROUTE:
      if (state.routes[state.index].key === (action.route && action.route.key)) return state
    return NavigationStateUtils.push(state, action.route)

    case POP_ROUTE:
      if (state.index === 0 || state.routes.length === 1) return state
      return NavigationStateUtils.pop(state)

   default:
     return state

  }
}

export default navigationState
Run Code Online (Sandbox Code Playgroud)

这些方法处理push和pop以及如何设置导航栏后退(弹出)按钮:

  _renderScene (props) {
    const { route } = props.scene

    return (
      <route.component _handleNavigate={this._handleNavigate.bind(this)} {...route.passProps} actions={this.props}/>
    )
  }

  _handleBackAction() {
    if (this.props.navigation.index === 0) {
      return false
    }
    this.props.popRoute()
    return true
  }

  _handleNavigate(action) {
    switch (action && action.type) {
      case 'push':
        this.props.pushRoute(action.route)
        return true
      case 'back':
      case 'pop':
        return this._handleBackAction()
      default:
        return false
    }
  }

renderOverlay = (sceneProps) => {
if(0 < sceneProps.scene.index)
{
  return (
    <NavigationHeader
      {...sceneProps}
      renderLeftComponent={() => {
        switch(sceneProps.scene.route.title){
          case 'Home':
            return (
              <TouchableHighlight onPress={() => this._handleBackAction()}>
                <Text}>X</Text>
              </TouchableHighlight>
            )
          }
        }
      }
    />
  )
}
  }

  render() {
    return (
        <NavigationCardStack
          direction={this.props.navigation.routes[this.props.navigation.index].direction}
          navigationState={this.props.navigation}
          onNavigate={this._handleNavigate.bind(this)}
          renderScene={this._renderScene}
          renderOverlay={this.renderOverlay}
        />
    )
  }
Run Code Online (Sandbox Code Playgroud)

并通过如下组件调用:

const route = {
  home: {
    type: 'push',
    route: {
      key: 'home',
      title: 'Home',
      component: Home,
      direction: 'vertical',
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑控制台日志

在此输入图像描述 在此输入图像描述

编辑2继续

在此输入图像描述

编辑3幻灯片菜单

在此输入图像描述

rcl*_*lai 4

像这样调试你的导航减速器:

function navigationState (state = initialState, action) {
  switch(action.type) {
    case PUSH_ROUTE:
      console.log('action', action);
      if (state.routes[state.index].key === (action.route && action.route.key)) return state
      const newNavigationState = NavigationStateUtils.push(state, action.route);
      console.log('newNavigationState', newNavigationState);
      return newNavigationState;

    case POP_ROUTE:
      if (state.index === 0 || state.routes.length === 1) return state
      return NavigationStateUtils.pop(state)

   default:
     return state

  }
}
Run Code Online (Sandbox Code Playgroud)

编辑

由于这种方式NavigationStateUtils.push有效(请参阅此处),它需要一个全新的路由来推送到路由堆栈。根据您的导航流程,您无法再次使用它返回主页,您必须使用不同的功能,例如NavigationStateUtils.popNavigationStateUtils.reset以及其他功能(浏览该文件)。但是,您不仅限于 中的函数NavigationStateUtils,您可以在减速器中定义自己的修改,但您需要确保导航状态具有以下数据格式:

{
  // `routes` needs to be an array of objects and each object
  // needs to have a unique `key` property
  routes: [{
    key: 'anything', // must be unique in this `routes` array
    ...anyOtherData
  }],
  // `index` is required, and has to be a number that refers 
  // to the index of the route in the routes array that is active
  index: 1,
}
Run Code Online (Sandbox Code Playgroud)

编辑

根据您在评论中的要求,每次您点击抽屉项目时,都需要重置您的导航路线堆栈,以该路线为起点,然后您可以开始推送和弹出。

function navigationState (state = initialState, action) {
  switch(action.type) {
    case PUSH_ROUTE:
      if (state.routes[state.index].key === (action.route && action.route.key)) return state
      return NavigationStateUtils.push(state, action.route)

    case POP_ROUTE:
      if (state.index === 0 || state.routes.length === 1) return state
      return NavigationStateUtils.pop(state)

    case DRAWER_ITEM_PRESS:
      // `action.route` is simply the route object of the drawer item you pressed
      return NavigationStateUtils.reset(state, [action.route], 0);
    default:
      return state;
  }
}
Run Code Online (Sandbox Code Playgroud)

另一方面,我认为根据您的要求,尝试使用可能是一个好主意,react-native-router-flux因为您将能够定义您的路由子路由react-native-drawerRedux集成和集成。