Actions must be plain object. Use custom middlewar

2020-04-08 11:22发布

问题:

I am using Redux,redux-thunk with react. I am returning an object but still getting the error.

authActions.js

export function register(){
return (dispatch)=>{
    console.log("in register action");
    dispatch({type:'auth_user'})
}
}

calling this action from Register.js using connect and props

import  * as actions  from '../actions/authActions';

class RegisterForm extends React.Component{

handleRegister = (e)=>{
    e.preventDefault();
    console.log("inside handle register");
    console.log(this.props);
    this.props.register();
 }
}
var Register = connect(mapStateToProps,actions)(RegisterForm);

Error is

Actions must be plain objects. Use custom middleware for async actions.

EDIT 1

Implemented redux-thunk like below.

import thunk from 'redux-thunk';


const store = createStore(authReducer,applyMiddleware(
                        thunk, 
                        loggerMiddleware
                        ),window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());


ReactDOM.render(
<Provider store={store}>
    <App />
</Provider>, 
document.getElementById('root'));

The code can be found on github using link https://github.com/abhikulshrestha22/social-network/tree/master/client

回答1:

You're using register from mapDispatchToProps:

this.props.register();

But it's just:

var Register = connect(mapStateToProps,actions)(RegisterForm);

So, calling register wouldn't work because it's in actions, actions.register:

var Register = connect(mapStateToProps,{register: actions.register})(RegisterForm);

Now, it should fix your issue.



回答2:

actions/index.js

// with thunk
export const register = () => dispatch => (
   dispatch({ type: 'auth_user' })
)

// without thunk
export const register = () => ({ type: 'auth_user' })

component/example.js

import React from 'react';
import { connect } from 'react-redux';
import { register } from '../actions';

const Example = ({ register }) => (
   <button onClick={register}>Register</button>
)

export default connect(null, { register })(Example);

reducers/index.js

const authReducer = (state=false, {type, payload}) => {
  switch(type) {
    case 'auth_user': return !state;
    default: return state;
  }
}


回答3:

There is nothing wrong with the current setup that you showed above.

I think your mapDispatchToProps may be the root cause of this problem.

You should declare your connect likes this

export default connect(
  null,
  { register }
)(Register);

instead of (if I'm not wrong)

const mapDispatchToProps = dispatch => {
  return {
    register: () => {
      dispatch(register());
    }
  };
};

export default connect(
  null,
  mapDispatchToProps
)(Register);

That's my guess. Hope this may help you.



回答4:

handleRegister = (e) => {
  ...
  this.props.dispatch(register());
}

Of course:

  • Apply redux-thunk middleware
  • In Register.js import register() action
  • Connect Register component to Redux store with react-redux connect()

EDIT:

If this simplified code (without mapDispatchToProps) doesn't work, something is wrong with your question. Maybe your action payload contains something that's not a plain object? E.g. promise returned by axios?

Code Sandbox according to your question, everything seems to work fine: https://codesandbox.io/s/j2mny6rvnv