本文介绍了使用 Redux 时,动作必须是普通对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我收到类似的错误动作必须是普通对象.使用自定义中间件进行异步操作在使用 react redux 时.我正在开发具有登录功能的应用程序.这是我的代码.
组件
import React, { Component } from 'react';从 'prop-types' 导入 PropTypes;从'react-redux'导入{connect};从redux"导入{bindActionCreators};从material-ui/Paper"导入纸张;从 'material-ui/TextField' 导入 TextField;从'material-ui/RaisedButton'导入RaisedButton;import * as AuthActions from '../../actions/AuthAction';从material-ui/styles/colors"导入 {blueGrey50,lightBlue500};常量样式 = {高度:350,宽度:370,左边距:80,边距:380,边距顶部:80,底边距:50,文本对齐:'居中',显示:'内联块',backgroundColor: blueGrey50,填充顶部:20,};常量样式 1 = {颜色:浅蓝色500};const style2 = {保证金:12,};类登录扩展组件{构造函数(道具){超级(道具);this.state = {电子邮件: '',密码: ''};}唱歌=()=>{console.log('登录');this.props.SigninActions.signIn({email:this.state.email,password:this.state.password});this.setState({email: '',password: '',loading:true});console.log('完成发送到动作');}使成为() {返回 (<div style={{backgroundImage: "url(" + "https://addmeskype.files.wordpress.com/2015/09/d62cb-teenagers-offlinle-online.jpg" + ")",宽度:1301,高度:654}}><Paper style={style} zDepth={2}><h1 style={style1}><center>登录</center></h1><TextField hintText="Email";floatLabelText="电子邮件"onChange={e=>{this.setState({email:e.target.value})}}/><TextFieldhintText=密码"floatLabelText="密码";类型=密码"onChange={p=>{this.setState({password:p.target.value})}}/><br/><br/><RaisedButton label="Sign In";primary={true} style={style2} onTouchTap={this.singin}/></纸>{(this.props.isError)?<span>电子邮件或密码组合错误!</span>:<div>没有错误</div>}
);}}登录.PropTypes = {isError: PropTypes.bool,登录操作:PropTypes.object}const mapStateToProps = (state,ownProps) =>{返回 {isError: state.isError}}const mapDispatchToProps = (调度) =>{返回 {SigninActions:bindActionCreators(AuthActions,dispatch)};}导出默认连接(mapStateToProps,mapDispatchToProps)(登录);
操作
从'axios'导入axios;从'jwt-decode'导入jwtDecode;从 '../constants/user' 导入 { SIGN_UP_REQUEST, SIGN_IN_REQUEST, GET_USER_DETAILS, UPDATE_USER_DETAILS };export const getUserDetails=(email)=>{axios.get('http://localhost:3030/user',电子邮件).then((数据)=>{控制台日志(数据);返回 ({类型:GET_USER_DETAILS,用户:data.data});}).catch((错误)=>{console.log('err', 错误);});}export const updateUserDetails=(user)=>{axios.put('http://localhost:3030/user',用户).then((数据)=>{控制台日志(数据);返回 ({类型:UPDATE_USER_DETAILS,用户:data.data});}).catch((错误)=>{console.log('err', 错误);});}
减速器
import { SIGN_UP_REQUEST, SIGN_IN_REQUEST} from '../constants/user';常量初始状态 = {加载:假,isError: 假};导出默认函数用户(状态 = 初始状态,动作){开关(动作.类型){情况 SIGN_UP_REQUEST:return Object.assign({},state,{isError:action.data.isError});情况 SIGN_IN_REQUEST:return Object.assign({},state,{isError:action.data.isError});默认:返回状态;}}
Rootreducer
import { combineReducers } from 'redux';从'./ChatReducer'导入ChatReducer;从 './UserReducer' 导入 UserReducer;导出默认的 combineReducers({聊天:ChatReducer,用户:UserReducer})
商店
import { createStore, applyMiddleware } from 'redux';从redux-thunk"导入 thunk;从'../reducers/RootReducer'导入RootReducer;导出默认值() =>{返回 createStore(RootReducer,window.__REDUX_DEVTOOLS_EXTENSION__ &&window.__REDUX_DEVTOOLS_EXTENSION__());}
浏览器将错误显示为
如何克服这个问题?.我对 redux 很陌生.
解决方案
Vanilla redux 只处理普通的对象操作,比如
{ type: SOME_ACTION, ...parameters }
同步返回.
如果你想返回 Promises,你需要考虑使用像 redux-thunk 这样的中间件或者,实际上,除了来自动作创建者的普通对象之外的任何东西(或者,在这种情况下,处理异步动作).
参见:如何调度带有超时的 Redux 操作?
问题有两方面:
第一:
export const getUserDetails = (email) =>{axios.put('http://localhost:3030/user', user) .then((data) => {返回 {类型:UPDATE_USER_DETAILS,用户:data.data};});});
您在承诺 (axios.put
) 内返回一个操作,但您没有返回承诺 - javascript 无法按照您的预期工作.return
,在这种情况下,仅限于最近的父作用域;在这种情况下,promise 主体.根据您目前的情况,getUserDetails
动作创建者的返回类型是 undefined
.
//这在技术上仍然是*错误的*,见下文export const getUserDetails = (email) =>{//注意下一行的返回return axios.put('http://localhost:3030/user', user) .then((data) => {返回 {类型:UPDATE_USER_DETAILS,用户:data.data};});});
返回一个 Promise
仍然没有真正解决您的问题.
第二:使用 redux-thunk 时,你将你的动作包装在一个像
这样的函数中
export const getUserDetails = (email) =>{返回(调度)=>{return axios.put('http://localhost:3030/user', user) .then((data) => {//这是触发动作的地方派遣({类型:UPDATE_USER_DETAILS,用户:data.data});//如果要访问这个API调用的结果,可以在这里返回//返回的 promise 将解析为您在此处返回的任何内容返回数据;});}});
当您绑定动作创建者时,它会在保留方法签名的同时解开"创建者 - 您可以像平常一样使用它
this.props.getUserDetails("[email protected]").then((data) => {//可选的已解决承诺})
Im getting an error likeActions must be plain objects. Use custom middleware for async actionswhile using react redux. Im developing an application with a login functionality. Here is my code.
component
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import Paper from 'material-ui/Paper';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
import * as AuthActions from '../../actions/AuthAction';
import {blueGrey50,lightBlue500} from 'material-ui/styles/colors';
const style = {
height: 350,
width: 370,
marginLeft: 80,
marginRight: 380,
marginTop: 80,
marginBottom: 50,
textAlign: 'center',
display: 'inline-block',
backgroundColor: blueGrey50,
paddingTop: 20,
};
const style1 = {
color: lightBlue500
};
const style2 = {
margin: 12,
};
class Login extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: ''
};
}
singin=()=>{
console.log('signing in');
this.props.SigninActions.signIn({email:this.state.email,password:this.state.password});
this.setState({email: '',password: '',loading:true});
console.log('done sending to actions');
}
render() {
return (
<div style={{backgroundImage: "url(" + "https://addmeskype.files.wordpress.com/2015/09/d62cb-teenagers-offlinle-online.jpg" + ")",
width:1301, height:654}}>
<Paper style={style} zDepth={2}>
<h1 style={style1}><center>Sign In</center></h1>
<TextField hintText="Email" floatingLabelText="Email" onChange={e=>{this.setState({email:e.target.value})}}/>
<TextField hintText="Password" floatingLabelText="Password" type="password" onChange={p=>{this.setState({password:p.target.value})}}/>
<br/><br/>
<RaisedButton label="Sign In" primary={true} style={style2} onTouchTap={this.singin}/>
</Paper>
{
(this.props.isError)? <span>Email or Password combination is wrong!</span> : <div>No errors</div>
}
</div>
);
}
}
Login.PropTypes = {
isError: PropTypes.bool,
SigninActions: PropTypes.object
}
const mapStateToProps = (state,ownProps) => {
return {
isError: state.isError
}
}
const mapDispatchToProps = (dispatch) => {
return {
SigninActions:bindActionCreators(AuthActions,dispatch)
};
}
export default connect(mapStateToProps,mapDispatchToProps)(Login);
Actions
import axios from 'axios';
import jwtDecode from 'jwt-decode';
import { SIGN_UP_REQUEST, SIGN_IN_REQUEST, GET_USER_DETAILS, UPDATE_USER_DETAILS } from '../constants/user';
export const getUserDetails=(email)=>{
axios.get('http://localhost:3030/user',
email
)
.then((data)=>{
console.log(data);
return ({
type: GET_USER_DETAILS,
user:data.data
});
})
.catch((error)=>{
console.log('err', error);
});
}
export const updateUserDetails=(user)=>{
axios.put('http://localhost:3030/user',
user
)
.then((data)=>{
console.log(data);
return ({
type: UPDATE_USER_DETAILS,
user:data.data
});
})
.catch((error)=>{
console.log('err', error);
});
}
Reducer
import { SIGN_UP_REQUEST, SIGN_IN_REQUEST} from '../constants/user';
const initialState = {
loading: false,
isError: false
};
export default function User(state = initialState, action) {
switch (action.type) {
case SIGN_UP_REQUEST:
return Object.assign({},state,{isError:action.data.isError});
case SIGN_IN_REQUEST:
return Object.assign({},state,{isError:action.data.isError});
default:
return state;
}
}
Rootreducer
import { combineReducers } from 'redux';
import ChatReducer from './ChatReducer';
import UserReducer from './UserReducer';
export default combineReducers({
chat: ChatReducer,
user: UserReducer
})
Store
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import RootReducer from '../reducers/RootReducer';
export default() => {
return createStore(RootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
}
The browser displays the error as
How to overcome this issue?. im quite new to redux.
解决方案
Vanilla redux only handles plain object actions such as
{ type: SOME_ACTION, ...parameters }
returned synchronously.
You need to look into using middleware like redux-thunk if you want to return Promises or, really, anything other than a plain object from your action creators (or, in this case, handle asynchronous actions).
see this: How to dispatch a Redux action with a timeout?
edit:
The problem is kind of two fold:
first:
export const getUserDetails = (email) => {
axios.put('http://localhost:3030/user', user) .then((data) => {
return {
type: UPDATE_USER_DETAILS,
user:data.data
};
});
});
you're returning an action inside the promise (axios.put
) but you're not returning the promise - javascript doesn't work how you're intending it to work. return
, in this case, is limited to the nearest parent scope; in this case the promise body. Just given what you have currently, the return type of the getUserDetails
action creator is undefined
.
// this is still technically *wrong*, see below
export const getUserDetails = (email) => {
// notice the return on the next line
return axios.put('http://localhost:3030/user', user) .then((data) => {
return {
type: UPDATE_USER_DETAILS,
user:data.data
};
});
});
returns a Promise<Action>
which still doesn't really solve your problem.
second:When working with redux-thunk, you wrap your action in a function like
export const getUserDetails = (email) => {
return (dispatch) => {
return axios.put('http://localhost:3030/user', user) .then((data) => {
// this is where the action is fired
dispatch({
type: UPDATE_USER_DETAILS,
user:data.data
});
// if you want to access the result of this API call, you can return here
// the returned promise will resolve to whatever you return here
return data;
});
}
});
when you bind the action creator, it will "unwrap" the creator while keeping the method signature - you use it like you would normally
this.props.getUserDetails("[email protected]").then((data) => {
// optional resolved promise
})
这篇关于使用 Redux 时,动作必须是普通对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!