"Actions must be plain objects. Use custom middleware for async actions." 在使用 redux-thunk 时
"Actions must be plain objects. Use custom middleware for async actions." while using redux-thunk
我正在学习此 link 中的教程:http://www.thegreatcodeadventure.com/react-redux-tutorial-part-ii-react-router-and-container-components/
但是当 handleSubmit()
函数被触发时,我得到一个错误:
Error: Actions must be plain objects. Use custom middleware for async actions.
但我使用 redux-thunk 作为中间件。有什么东西不见了吗?
我正在使用 Antd 作为 UI 框架。
组件
import React, { Component } from 'react';
import compose from 'recompose/compose';
import { Form, Icon, Input, Button, Checkbox } from 'antd';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as sessionActions from './actions/sessionActions';
const FormItem = Form.Item;
class Login extends Component {
constructor(props){
super(props);
this.state = {credentials: {username: '', password: ''}};
this.handleSubmit = this.handleSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
onChange(event) {
const field = event.target.name;
const credentials = this.state.credentials;
credentials[field] = event.target.value;;
return this.setState({credentials: credentials});
}
handleSubmit = (event) => {
event.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
//console.log(this.props.actions);
this.props.actions.logInUser(this.state.credentials);
}
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'username missing!' }],
})(
<Input
name="username"
value={this.state.credentials.username}
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username o email"
onChange={this.onChange}/>
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Password missing!' }],
})(
<Input
name="password"
value={this.state.credentials.password}
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
onChange={this.onChange}/>
)}
</FormItem>
<FormItem>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: false,
})(
<Checkbox>Ricordami</Checkbox>
)}
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
</FormItem>
</Form>
);
}
}
const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(sessionActions, dispatch)
};
}
export default compose(connect(null, mapDispatchToProps), Form.create())(Login);
sessionReducer.js
import * as types from '../actions/actionTypes';
import initialState from './initialState';
export default function sessionReducer(state = initialState.session, action) {
switch(action.type) {
case types.LOG_IN_SUCCESS:
this.context.history.push('/')
return !!sessionStorage.jwt
default:
return state;
}
}
sessionActions.js
import * as types from './actionTypes';
import sessionApi from '../api/sessionApi';
export function loginSuccess() {
return {type: types.LOG_IN_SUCCESS}
}
export function logInUser(credentials) {
return function(dispatch) {
return sessionApi.login(credentials).then(response => {
sessionStorage.setItem('jwt', response.jwt);
dispatch(loginSuccess());
}).catch(error => {
throw(error);
});
};
}
sessionApi.js(登录)
import React from 'react'
var axios = require('axios');
var qs = require('qs');
class SessionApi {
static login(credentials){
axios.post('http://localhost:5000/login', qs.stringify({auth: credentials}))
.then(response => {
console.log(response);
return response.json();
}),
error => {
console.log(error);
return error;
};
}
}
店铺配置
import {createStore, applyMiddleware} from 'redux';
import rootReducer from '../reducers/rootReducer';
import thunkMiddleware from 'redux-thunk';
import logger from 'redux-logger'
export default function configureStore() {
return createStore(
rootReducer,
applyMiddleware(thunkMiddleware, logger),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
);
}
根据错误,我认为您的商店设置没有正确应用中间件。尝试以下方法创建商店。
const middlewares = [thunkMiddleware, logger];
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(...middlewares))
);
通过这种方法,composeEnhancers
函数将在生产中使用 compose
或在开发中使用来自 devtools 的函数。那么你的中间件应该可以工作了。
我正在学习此 link 中的教程:http://www.thegreatcodeadventure.com/react-redux-tutorial-part-ii-react-router-and-container-components/
但是当 handleSubmit()
函数被触发时,我得到一个错误:
Error: Actions must be plain objects. Use custom middleware for async actions.
但我使用 redux-thunk 作为中间件。有什么东西不见了吗? 我正在使用 Antd 作为 UI 框架。
组件
import React, { Component } from 'react';
import compose from 'recompose/compose';
import { Form, Icon, Input, Button, Checkbox } from 'antd';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import * as sessionActions from './actions/sessionActions';
const FormItem = Form.Item;
class Login extends Component {
constructor(props){
super(props);
this.state = {credentials: {username: '', password: ''}};
this.handleSubmit = this.handleSubmit.bind(this);
this.onChange = this.onChange.bind(this);
}
onChange(event) {
const field = event.target.name;
const credentials = this.state.credentials;
credentials[field] = event.target.value;;
return this.setState({credentials: credentials});
}
handleSubmit = (event) => {
event.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
//console.log(this.props.actions);
this.props.actions.logInUser(this.state.credentials);
}
});
}
render() {
const { getFieldDecorator } = this.props.form;
return (
<Form onSubmit={this.handleSubmit} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: 'username missing!' }],
})(
<Input
name="username"
value={this.state.credentials.username}
prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
placeholder="Username o email"
onChange={this.onChange}/>
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: 'Password missing!' }],
})(
<Input
name="password"
value={this.state.credentials.password}
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
type="password"
placeholder="Password"
onChange={this.onChange}/>
)}
</FormItem>
<FormItem>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: false,
})(
<Checkbox>Ricordami</Checkbox>
)}
<Button type="primary" htmlType="submit" className="login-form-button">
Log in
</Button>
</FormItem>
</Form>
);
}
}
const mapDispatchToProps = (dispatch) => {
return {
actions: bindActionCreators(sessionActions, dispatch)
};
}
export default compose(connect(null, mapDispatchToProps), Form.create())(Login);
sessionReducer.js
import * as types from '../actions/actionTypes';
import initialState from './initialState';
export default function sessionReducer(state = initialState.session, action) {
switch(action.type) {
case types.LOG_IN_SUCCESS:
this.context.history.push('/')
return !!sessionStorage.jwt
default:
return state;
}
}
sessionActions.js
import * as types from './actionTypes';
import sessionApi from '../api/sessionApi';
export function loginSuccess() {
return {type: types.LOG_IN_SUCCESS}
}
export function logInUser(credentials) {
return function(dispatch) {
return sessionApi.login(credentials).then(response => {
sessionStorage.setItem('jwt', response.jwt);
dispatch(loginSuccess());
}).catch(error => {
throw(error);
});
};
}
sessionApi.js(登录)
import React from 'react'
var axios = require('axios');
var qs = require('qs');
class SessionApi {
static login(credentials){
axios.post('http://localhost:5000/login', qs.stringify({auth: credentials}))
.then(response => {
console.log(response);
return response.json();
}),
error => {
console.log(error);
return error;
};
}
}
店铺配置
import {createStore, applyMiddleware} from 'redux';
import rootReducer from '../reducers/rootReducer';
import thunkMiddleware from 'redux-thunk';
import logger from 'redux-logger'
export default function configureStore() {
return createStore(
rootReducer,
applyMiddleware(thunkMiddleware, logger),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
);
}
根据错误,我认为您的商店设置没有正确应用中间件。尝试以下方法创建商店。
const middlewares = [thunkMiddleware, logger];
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
composeEnhancers(applyMiddleware(...middlewares))
);
通过这种方法,composeEnhancers
函数将在生产中使用 compose
或在开发中使用来自 devtools 的函数。那么你的中间件应该可以工作了。