【问题标题】:Actions must be plain objects while using Redux使用 Redux 时操作必须是普通对象
【发布时间】:2017-10-25 06:16:00
【问题描述】:

我收到类似的错误 动作必须是普通对象。使用自定义中间件进行异步操作 在使用 react redux 时。我正在开发一个具有登录功能的应用程序。这是我的代码。

组件

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);

操作

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);
      });
}

减速器

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
})

商店

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__());
}

浏览器将错误显示为

如何克服这个问题?我对 redux 很陌生。

【问题讨论】:

    标签: reactjs redux react-redux


    【解决方案1】:

    Vanilla redux 只处理普通的对象操作,例如

    { type: SOME_ACTION, ...parameters }

    同步返回

    如果您想返回 Promises 或者实际上是来自动作创建者的普通对象以外的任何东西(或者,在这种情况下,处理异步动作),您需要考虑使用像 redux-thunk 这样的中间件。

    看到这个:How to dispatch a Redux action with a timeout?

    编辑:

    问题有两个方面:

    第一:

    export const getUserDetails = (email) => {
        axios.put('http://localhost:3030/user', user) .then((data) => {
            return {
                type: UPDATE_USER_DETAILS,
                user:data.data
            };
        });
    });
    

    您在承诺 (axios.put) 中返回了一个操作,但您没有返回承诺 - javascript 无法按照您的预期工作。 return,在这种情况下,仅限于最近的父范围;在这种情况下,承诺主体。就你目前的情况来看,getUserDetails 动作创建者的返回类型是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
            };
        });
    });
    

    返回一个 Promise&lt;Action&gt; 仍然不能真正解决您的问题。

    秒: 当使用 redux-thunk 时,你将你的动作包装在一个函数中,比如

    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; 
            });
        }
    });
    

    当您绑定动作创建者时,它会“解开”创建者,同时保留方法签名 - 您可以像平常一样使用它

    this.props.getUserDetails("email@domain.com").then((data) => {
        // optional resolved promise
    })
    

    【讨论】:

    • 我使用了 redux-thunk 但我仍然遇到同样的错误。我需要在 Actions 中调度函数吗?我正在使用 bindActionCreators。
    • 不过,您需要从您的操作中返回 thunk。我会更新我的评论。
    • 我刚刚注意到您正在从承诺内部进行尝试,但实际上并未返回承诺......
    • 我现在很困惑。您能否借助一些代码进行解释。我已经尝试了一切,但我不知道如何解决这个问题。
    • 感谢它的工作,我不得不使用 redux 中的“compose”,因为我使用了一些中间件而不是 redux-thunk
    猜你喜欢
    • 2017-11-28
    • 1970-01-01
    • 2023-03-14
    • 2018-07-08
    • 2018-12-23
    • 2020-06-13
    • 2018-03-23
    • 2017-05-09
    • 1970-01-01
    相关资源
    最近更新 更多