使用带有react-navigation和redux集成的嵌套导航器

时间:2018-04-08 20:33:42

标签: react-native react-redux react-navigation

我正在尝试使用带有redux集成的嵌套导航器,但是应用程序无法加载时出现以下错误:

Error

一切正常,直到我为登录流程添加了第二层导航器。

我该如何做到这一点?

以下是导航器的完整代码,并将其与redux集成:

import React, { Component } from 'react';
import { BackHandler } from "react-native";

import { connect } from 'react-redux';
import { fromJS } from 'immutable';

import { dogTypes } from '../ducks/dog';

import { StackNavigator, addNavigationHelpers, NavigationActions } from 'react-navigation';
import { createReduxBoundAddListener, createReactNavigationReduxMiddleware } from 'react-navigation-redux-helpers';

import MainScreen from '../screens/MainScreen';
import SecondScreen from '../screens/SecondScreen';
import AuthLoadingScreen from '../screens/AuthLoadingScreen';
import AuthScreen from '../screens/AuthScreen';

import HeaderWithMenu from '../components/Headers/HeaderWithMenu';
import HeaderWithBack from '../components/Headers/HeaderWithBack';

import Translations from '../translations/screens';

const MainNavigator = StackNavigator({
  LoginFlow: {
    screen: StackNavigator({
      AuthLoading: AuthLoadingScreen,
      Auth: AuthScreen,
    },
    {
      initialRouteName: 'AuthLoading',
    })
  },
  MainFlow: {
    screen: StackNavigator({
      Main: {
        screen: MainScreen,
        navigationOptions: ({navigation}) => ({
          header: <HeaderWithMenu title={Translations.t('mainScreen')}/>
        })
      },
      Second: { 
        screen: SecondScreen,
        navigationOptions: ({navigation}) => ({
          header: <HeaderWithBack title={Translations.t('secondScreen')} navigation={navigation}/>
        })
      },
    },
    {
      initialRouteName: 'Main'
    })
  }
},
{
  initialRouteName: 'MainFlow'
});

const initialState = fromJS(
  {
    index: 0,
    routes: [
      {
        index: 0,
        key: 'MainFlow',
        routeName: 'MainFlow',
        routes: [
          {
            key: 'Main',
            routeName: 'Main'
          }
        ]
      }
    ]
  }
);

export const mainNavReducer = (state = initialState, action) => {
  let nextState;
  switch (action.type) {
    case dogTypes.DOG_BIGGER:
      nextState = state.merge(MainNavigator.router.getStateForAction(
        MainNavigator.router.getActionForPathAndParams('Second'),
        state.toJS()
      ));
      break;
    default:
      nextState = state.merge(MainNavigator.router.getStateForAction(action, state.toJS()));
      break;
  }

  // Simply return the original `state` if `nextState` is null or undefined.
  return nextState || state;
};

export const mainNavMiddleware = createReactNavigationReduxMiddleware(
  "root",
  state => state.nav,
)

const addListener = createReduxBoundAddListener("root");

class App extends Component {
  componentDidMount() {
    BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
  }
  componentWillUnmount() {
    BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
  }
  onBackPress = () => {
    const { dispatch, nav } = this.props;
    if (nav.index === 0) {
      return false;
    }
    dispatch(NavigationActions.back());
    return true;
  };

  render() {
    return (
      <MainNavigator navigation={addNavigationHelpers({
        dispatch: this.props.dispatch,
        state: this.props.nav,
        addListener,
      })} />
    );
  }
}

const mapStateToProps = (state) => {
  return {
    nav: state.get('nav').toJS()
  }
};

export const MainNavigatorComponent = connect(mapStateToProps)(App);

3 个答案:

答案 0 :(得分:0)

StackNavigator应该自己定义,每个StackNavigator都需要在定义嵌套位置之前定义。

所以我会怎么做:

const LoginFlow = StackNavigator({})

const MainFlow = StackNavigator({})

const MainNavigator = StackNavigator({
  Login: {
    screen: LoginFlow //screen is the stack navigator defined above
  },
  Main: {
    screen: MainFlow //screen is the stack navigator defined above
  }

})

另外,您的初始状态是正确的请阅读docs,您可以直接复制粘贴设置Reducer / store并与redux集成的方式。

答案 1 :(得分:0)

这个问题实际上是反应导航库中的直接问题。我将我的版本更新到最新版本(此时为2.0.0-rc.1),它解决了这个问题。

我仍然喜欢@NewToCoding定义他的导航器的方式,并且不得不稍微更改initialState。这是最终的工作代码:

const LoginFlow = StackNavigator({
  Auth: AuthScreen,
},
{
  initialRouteName: 'Auth',
});

const MainFlow = StackNavigator({
  Main: {
    screen: MainScreen,
    navigationOptions: ({navigation}) => ({
      header: <HeaderWithMenu title={Translations.t('mainScreen')}/>
    })
  },
  Second: { 
    screen: SecondScreen,
    navigationOptions: ({navigation}) => ({
      header: <HeaderWithBack title={Translations.t('secondScreen')} navigation={navigation}/>
    })
  },
},
{
  initialRouteName: 'Main'
});

const MainNavigator = SwitchNavigator({
  AuthLoading: AuthLoadingScreen,
  App: MainFlow,
  Auth: LoginFlow,
},
{
  initialRouteName: 'AuthLoading'
});

const initialState = fromJS(MainNavigator.router.getStateForAction(NavigationActions.navigate({ routeName: 'AuthLoading' })));

export const mainNavReducer = (state = initialState, action) => {
  let nextState;
  switch (action.type) {
    case dogTypes.DOG_BIGGER:
      nextState = state.merge(MainNavigator.router.getStateForAction(
        NavigationActions.navigate({ routeName: 'Second' }),
        state.toJS()
      ));
      break;
    default:
      nextState = state.merge(MainNavigator.router.getStateForAction(action, state.toJS()));
      break;
  }

  // Simply return the original `state` if `nextState` is null or undefined.
  return nextState || state;
};

答案 2 :(得分:0)

这是React Navigation的问题。我只是在package.json上更改了React Navigation版本。我花了很多时间来解决这个问题: 代替这个

"react-navigation": "^2.18.2",
"react-navigation-redux-helpers": "^2.0.9",

我将其更改为此

"react-navigation": "2.18.2",
"react-navigation-redux-helpers": "^2.0.9",