Navaneethan Arun
Navaneethan Arun

Reputation: 386

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

I try to deal with ajax data using axom in my learning react,redux project and I have no idea how to dispatch an action and set the state inside a component

In component will mount

componentWillMount(){
  this.props.actions.addPerson();
}

Store

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

export default function configureStore() {
  return createStore(rootReducer, applyMiddleware(thunk));
}

In Action :

import * as types from "./action-types";
import axios from "axios";
export const addPerson = person => {
  var response = [];

  axios
    .get(`&&&&&&&&&&&`)
    .then(res => {
      response = res.data;

      return {
        type: types.ADD_PERSON,
        response
      };
    });
};

In reducer

import * as types from "../actions/action-types";

export default (state = [], action) => {
  console.log("action======>", action);
  switch (action.type) {
    case types.ADD_PERSON:
      console.log("here in action", action);
      return [...state, action.person];
    default:
      return state;
  }
};

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

Upvotes: 1

Views: 1037

Answers (3)

Chenxi Yuan
Chenxi Yuan

Reputation: 164

You should use dispatch for async function. Take a look of the redux-thunk's documentation: https://github.com/gaearon/redux-thunk

In Action:

import * as types from "./action-types";
import axios from "axios";

export const startAddPerson = person => {
  return (dispatch) => {
    return axios
      .get(`https://599be4213a19ba0011949c7b.mockapi.io/cart/Cart`)
      .then(res => {
        dispatch(addPersons(res.data));
      });
  }
};

export const addPersons = personList => {
  return {
    type: types.ADD_PERSON,
    personList
  };
}

In PersonComponent:

class Person extends Component {
  constructor(props){ 
    super(props);
  }
  componentWillMount() {
    this.props.dispatch(startAddPerson())
  }

  render() {
    return (
      <div>
      <h1>Person List</h1>
      </div>
    );
  }
}

export default Redux.connect()(Person);

Upvotes: 1

thedude
thedude

Reputation: 9822

You need two actions here: postPerson and addPerson.

postPerson will perform the API request and addPerson will update the store:

const addPerson = person => {
    return {
        type: types.ADD_PERSON,
        person,
    }
}

const postPerson = () => {
   return (dispatch, getState) => {
       return axios.get(`http://599be4213a19ba0011949c7b.mockapi.io/cart/Cart`)
                   .then(res => dispatch(addPerson(res.data)))
   }
}

in your component, call postPerson()

Upvotes: 1

Jeremy Schrader
Jeremy Schrader

Reputation: 396

You use the redux-thunk library which gives you access to the "getState" and "dispatch" methods. I see that that has been added by Chenxi to your question. Run your async operation first within your action and then call "dispatch" with your simple action action creator, which will return the simple object that redux is looking for.

Here is what your async action creator and your simple action creator(broken out into two action creators) will look like:

export const addPersonAsync = (person) => {
  return (dispatch) => {
    var response = [];

    axios
      .get(`http://599be4213a19ba0011949c7b.mockapi.io/cart/Cart`)
      .then(res => {
        response = res.data;

        dispatch(addPerson(response));
      });
  };
};


export const addPerson = (response) => ({
  type: types.ADD_PERSON,
  response
});

From your component, you'll now call the "addPersonAsync" action creator.

Upvotes: 0

Related Questions