0
votes

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

This is the error and this function is pointed

this.props.registerUser(newUser);

see the next code snippet!

redux-thunk is used for referring plain js object but not working

This is my action creator file :

import { GET_ERRORS } from "./types";
import axios from "axios";

// Register User
export const registerUser = userData => dispatch => {
axios
.post("/api/users/register", userData)
.then(res => console.log(res))
.catch(err =>
  dispatch({
    type: GET_ERRORS,
    payload: err.response.data
  })
 );
};

This is my react registration page :

import React, { Component } from "react";
import PropTypes from "prop-types";
// import { withRouter } from 'react-router-dom';
import classnames from "classnames";
import { connect } from "react-redux";
import { registerUser } from "../../actions/authActions";

class Register extends Component {
  constructor() {
    super();
    this.state = {
      name: "",
      email: "",
      password: "",
      password2: "",
      errors: {}
    };

    this.onChange = this.onChange.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.errors) {
      this.setState({ errors: nextProps.errors });
    }
  }

  onChange(event) {
    this.setState({ [event.target.name]: event.target.value });
  }
  onSubmit(event) {
    event.preventDefault();
    const newUser = {
      name: this.state.name,
      email: this.state.email,
      password: this.state.password,
      confirm_password: this.state.password2
    };
    this.props.registerUser(newUser);
  }
  render() {
    const { errors } = this.state;

    return (
      <div className="register">
        <div className="container">
          <div className="row">
            <div className="col-md-8 m-auto">
              <h1 className="display-4 text-center">Sign Up</h1>
              <p className="lead text-center">
                Create your SocioStalker account
              </p>
              <form noValidate onSubmit={this.onSubmit}>
                <div className="form-group">
                  <input
                    type="text"
                    className={classnames("form-control form-control-lg", {
                      "is-invalid": errors.name
                    })}
                    placeholder="Name"
                    name="name"
                    value={this.state.name}
                    onChange={this.onChange}
                  />
                  <div className="invalid-feedback">{errors.name}</div>
                </div>
                <div className="form-group">
                  <input
                    type="email"
                    className={classnames("form-control form-control-lg", {
                      "is-invalid": errors.email
                    })}
                    placeholder="Email Address"
                    name="email"
                    value={this.state.email}
                    onChange={this.onChange}
                  />
                  <div className="invalid-feedback">{errors.email}</div>

                  <small className="form-text text-muted">
                    This site uses Gravatar so if you want a profile image, use
                    a Gravatar email
                  </small>
                </div>
                <div className="form-group">
                  <input
                    type="password"
                    className={classnames("form-control form-control-lg", {
                      "is-invalid": errors.password
                    })}
                    placeholder="Password"
                    name="password"
                    value={this.state.password}
                    onChange={this.onChange}
                  />
                  <div className="invalid-feedback">{errors.password}</div>
                </div>
                <div className="form-group">
                  <input
                    type="password"
                    className={classnames("form-control form-control-lg", {
                      "is-invalid": errors.confirm_password
                    })}
                    placeholder="Confirm Password"
                    name="password2"
                    value={this.state.password2}
                    onChange={this.onChange}
                  />
                  <div className="invalid-feedback">
                    {errors.confirm_password}
                  </div>
                </div>
                <input type="submit" className="btn btn-info btn-block mt-4" />
              </form>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

Register.propTypes = {
  registerUser: PropTypes.func.isRequired,
  auth: PropTypes.object.isRequired,
  errors: PropTypes.object.isRequired
};

const mapStateToProps = state => ({
  auth: state.auth,
  errors: state.errors
});

export default connect(
  mapStateToProps,
  { registerUser }
)(Register);

Store config file:

import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
import { composeWithDevTools } from "redux-devtools-extension";

const initialState = {};

const middleware = [thunk];
const store = createStore(
  rootReducer,
  initialState,
  compose(
    composeWithDevTools(),
    applyMiddleware(...middleware)
  )
);

export default store;
1
dispatch an action in .then() (similar to catch).. currently its just logging the data .... - Anirudh Mangalvedhekar
why its needed? will it fix the issiue ? - CryptoScroller
still not working - CryptoScroller
added a TEST_DISPATCH action and also added the reducer .then(res => dispatch({ type: TEST_DISPATCH })) - CryptoScroller
hmmm.. would you mind adding the code where you import and apply redux-thunk ? - Anirudh Mangalvedhekar

1 Answers

1
votes

Your store setup logic is wrong. You've got this:

compose(
    composeWithDevTools(),
    applyMiddleware(...middleware)
)

Instead, it should be:

composeWithDevTools(
    applyMiddleware(...middleware)
)

Please see the Redux docs page on "Configuring Your Store" for examples of how to correctly set up middleware and the DevTools Extension.

I'd also encourage you to try out our new redux-starter-kit package. It includes a configureStore function that does all that for you automatically.

Here's how you could simplify your startup file using configureStore:

import {configureStore} from "redux-starter-kit";
import rootReducer from "./reducers";

const store = configureStore({
    reducer : rootReducer,
});