使用redux-thunk仍遇‘Actions must be plain objects’错误,求排查原因
嘿,我之前也踩过这个坑!你明明配置了redux-thunk却还是碰到Error: Actions must be plain objects,大概率是这几个关键环节没做到位,咱们一步步排查:
很多人会犯“引入了thunk但没加到中间件链里”的错误,你得确保创建store时,把thunk通过applyMiddleware注入进去,尤其是和Redux DevTools一起使用时,要正确组合增强器:
import { createStore, applyMiddleware, compose } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; // 兼容Redux DevTools的写法 const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore( rootReducer, composeEnhancers(applyMiddleware(thunk)) // 必须把thunk放在这里! );
要是你只是import thunk但没在applyMiddleware里配置,那thunk等于没生效,Redux自然会拒绝非纯对象的action。
redux-thunk的核心是让action creator返回一个函数(而不是直接返回异步操作),这个函数会接收dispatch参数来分发纯对象action。你的sessionActions.js里的登录action应该是这样:
import sessionApi from './sessionApi'; // 正确的异步action creator写法 export const login = (credentials) => { return (dispatch) => { // 先分发一个请求开始的纯对象action dispatch({ type: 'LOGIN_REQUEST' }); // 调用异步API,之后分发成功/失败的action return sessionApi.login(credentials) .then(response => { dispatch({ type: 'LOGIN_SUCCESS', payload: response }); }) .catch(error => { dispatch({ type: 'LOGIN_FAILURE', payload: error }); }); }; };
要是你直接在action creator里调用sessionApi.login()并返回它的Promise,那这个action就不是纯对象,Redux会直接报错。
在你的登录组件里,要确保是通过Redux的dispatch来触发action creator,而不是直接调用它。比如用connect绑定action:
import { login } from './sessionActions'; import { connect } from 'react-redux'; import { Form, Button } from 'antd'; class LoginForm extends React.Component { handleSubmit = (values) => { // 正确:通过props.dispatch触发(connect自动注入) this.props.login(values); }; render() { return ( <Form onFinish={this.handleSubmit}> {/* Antd表单元素 */} <Button type="primary" htmlType="submit">登录</Button> </Form> ); } } // 把login action绑定到props export default connect(null, { login })(LoginForm);
要是你直接写login(values)而没通过dispatch(比如没做connect,或者手动调用时没包dispatch),那thunk中间件根本没机会处理这个异步函数,自然会报错。
虽然这不直接导致那个错误,但如果sessionApi.js里的登录方法没正确返回Promise,thunk里的then/catch会失效。比如:
// sessionApi.js 示例写法 export default { login: (credentials) => { return fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(credentials) }).then(res => res.json()); } };
先从前面三点查起,尤其是Store配置和action creator的写法,这俩是最常见的问题根源。
内容的提问来源于stack exchange,提问作者andrea56

