集成Redux与ReactNavigation时mapStateToProps返回undefined问题排查
问题分析与解决方案
嘿,我帮你拆解下遇到的这两个问题,都是和React Navigation 2.x的新用法以及Redux状态映射的小细节有关,咱们一步步来解决:
第一个错误:mapStateToProps() must return a plain object. Instead received undefined
从你说日志能打印出NavReducer的初始状态{index: 0, routes: Array(1)}来看,state.nav是存在的,那这个错误大概率是根Reducer合并时的key和你在mapStateToProps里取的key不匹配。
举个例子,如果你的根Reducer是这么写的:
import { combineReducers } from 'redux'; import AuthReducer from './AuthReducer'; import NavReducer from './NavReducer'; export default combineReducers({ auth: AuthReducer, navigation: NavReducer // 这里用的key是navigation而不是nav });
那你在mapStateToProps里取state.nav就会拿到undefined,虽然返回的是{navigation: undefined}(这本身是个普通对象),但后续逻辑出错可能会触发这个错误提示。当然也有可能是代码里的小语法问题,但从你给出的代码看,更可能是Reducer的key不匹配。
第二个错误:addNavigationHelpers is not a function
这个是核心问题!你用的是React Navigation 2.0.1,而addNavigationHelpers在2.x版本里已经不是直接从react-navigation导入的了,而且官方已经不再推荐用旧的Router组件,而是改用导航器(比如createStackNavigator)配合Redux集成的专用库react-navigation-redux-helpers。
具体修复步骤:
- 先安装Redux集成的辅助库:
npm install react-navigation-redux-helpers --save # 或者用yarn yarn add react-navigation-redux-helpers
- 重构你的导航配置,用2.x的方式创建Stack导航器:
新建一个Navigation.js文件(或者在原有文件里修改):
import { createStackNavigator, createAppContainer } from 'react-navigation'; import Login from './Login'; // 替换成你的Login组件路径 import EmployeeList from './EmployeeList'; // 替换成你的EmployeeList组件路径 // 创建Stack导航器,同时设置初始路由(你之前没设,建议加上) const AppNavigator = createStackNavigator({ Login: { screen: Login }, EmployeeList: { screen: EmployeeList } }, { initialRouteName: 'Login' }); // 生成可被Redux绑定的导航容器 export const AppContainer = createAppContainer(AppNavigator);
- 修改你的
RouterWithNavigationState组件,用新的Redux集成方式:
import React from 'react'; import { connect } from 'react-redux'; import { reduxifyNavigator } from 'react-navigation-redux-helpers'; import { AppContainer } from './Navigation'; // 将导航容器和Redux绑定 const ReduxifiedApp = reduxifyNavigator(AppContainer, 'root'); class RouterWithNavigationState extends React.Component { render() { return <ReduxifiedApp {...this.props} />; } } // 映射Redux状态到组件props,这里的state.nav要和根Reducer里的NavReducer key一致 const mapStateToProps = state => ({ state: state.nav, }); const mapDispatchToProps = dispatch => ({ dispatch, }); export default connect(mapStateToProps, mapDispatchToProps)(RouterWithNavigationState);
- 更新你的NavReducer,用导航器自带的方法生成初始状态:
// NavReducer.js import { AppNavigator } from './Navigation'; // 从导航器获取初始路由状态 const initialState = AppNavigator.router.getStateForAction( AppNavigator.router.getActionForPathAndParams('Login') ); export default (state = initialState, action) => { // 让导航器处理路由动作 const nextState = AppNavigator.router.getStateForAction(action, state); // 如果当前动作无法处理,返回原状态 return nextState || state; };
- 确保根Reducer里的key和mapStateToProps里的一致:
比如根Reducer里NavReducer的key是nav,那mapStateToProps里就取state.nav:
// rootReducer.js import { combineReducers } from 'redux'; import AuthReducer from './AuthReducer'; import NavReducer from './NavReducer'; export default combineReducers({ auth: AuthReducer, nav: NavReducer // 这里的key要和mapStateToProps里的对应 });
完成上面的修改后,两个错误应该都会消失。另外提醒下,设置initialRouteName很重要,这样App启动时会默认加载Login页面,符合你的业务流程。
内容的提问来源于stack exchange,提问作者SwethaG
相关产品推荐
相关产品推荐

