Redux调用含逻辑的Action Creator报错:type属性未定义
你遇到的这个错误,核心问题出在loadMenu和loadGame这两个action creator的写法上——它们是为了使用Redux Thunk处理带逻辑的action,但写法完全不符合Thunk的要求,导致dispatch的时候实际传递的是一个没有type属性的对象,触发了Redux的校验错误。
先看你当前的错误写法:
export const loadMenu=()=>({ function(dispatch,getState){ // ...逻辑 } })
这种写法是返回了一个对象,对象里有个名为function的属性,但Redux会把这个对象当成普通action来处理,而普通action必须要有type字段,所以自然报错。
而Redux Thunk要求的是:带逻辑的action creator应该返回一个函数,而不是对象。这个函数会被Thunk中间件捕获,传入dispatch和getState参数供你使用。
修正步骤
1. 修正loadMenu和loadGame的写法
把这两个action creator改成返回函数的形式,同时修正语法错误(比如括号不匹配的问题):
// Action.js 修正后的代码 import constants from "../gameConstants/constants"; // ...其他正确的action creator保持不变 export const loadMenu = () => { return (dispatch, getState) => { function handleSpacebar(event) { if (event.keyCode === 32) { dispatch(loadGame()); window.removeEventListener('keyup', handleSpacebar); console.log('here'); } } window.addEventListener('keyup', handleSpacebar); }; }; export const loadGame = () => { return (dispatch, getState) => { dispatch(startGame()); }; };
或者用箭头函数简化写法:
export const loadMenu = () => (dispatch, getState) => { const handleSpacebar = (event) => { if (event.keyCode === 32) { dispatch(loadGame()); window.removeEventListener('keyup', handleSpacebar); console.log('here'); } }; window.addEventListener('keyup', handleSpacebar); }; export const loadGame = () => (dispatch) => { dispatch(startGame()); };
2. 确保Redux Store已配置Thunk中间件
要让Thunk生效,你必须在创建Redux Store的时候添加Thunk中间件。如果你还没配置,需要这样做:
// store.js 示例代码 import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; const store = createStore( rootReducer, applyMiddleware(thunk) // 加入Thunk中间件 ); export default store;
3. 在组件中正确调用
你的Menu组件里的componentDidMount调用this.props.dispatch(loadMenu())是没问题的,修正action creator之后,这个调用就会正常触发Thunk函数,进而在空格键按下时dispatchstartGame。
另外,你也可以用mapDispatchToProps来绑定action creator,让代码更整洁:
// Menu.js 中修改connect部分 const mapDispatchToProps = (dispatch) => ({ loadMenu: () => dispatch(loadMenu()), // 其他action也可以在这里绑定 }); export default connect(mapStateToProps, mapDispatchToProps)(Menu); // 然后在componentDidMount中直接调用: componentDidMount() { this.props.loadMenu(); // ...其他代码 }
为什么直接dispatchstartGame没问题?
因为startGame是一个标准的同步action creator,它返回的是一个带有type字段的纯对象,符合Redux对普通action的要求,所以能正常工作。而你需要的带逻辑的action(比如监听键盘事件后再触发其他action)就必须用Thunk来实现,这就要求action creator返回函数而不是对象。
内容的提问来源于stack exchange,提问作者Sagar Sharma

