Search code examples
reactjsreduxaxiosmiddlewareredux-thunk

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


I have the following code which is throwing the error of the actions must be plain objects.i think the problem is with redux thunk but i am not able to rectify it.

action file-

import axios from "axios";
export const addBiller = (biller = {}) => {
return async dispatch => {
const res = await axios.post("/api/biller", biller);

dispatch({ type: "ADD_BILLER", payload: res.data });
};
};

my store-

import { createStore, combineReducers, applyMiddleware } from "redux";
import billerReducer from "../reducers/Billers";
import userReducer from "../reducers/User";
import billReducer from "../reducers/Bills";
import authReducer from "../reducers/Auth";
import reduxThunk from "redux-thunk";
export default () => {
 const store = createStore(
combineReducers(
  {
    Billers: billerReducer,
    Users: userReducer,
    Bills: billReducer,
    Auth: authReducer
  },
  applyMiddleware(reduxThunk)
  )
  );
 return store;
 };

the backend file-

 const mongoose = require("mongoose");
 const Biller = mongoose.model("biller");
 module.exports = app => {
 app.post("/api/biller", async (req, res) => {
 const { billerName, billerDescription } = req.body;
 const biller = new Biller({
  billerName: billerName,
  billerDescription: billerDescription
  });
   biller = await biller.save();
    res.send(biller);
    });
     };

my reducer-

   const BillerDefaultState = [];
   const billerReducer = (state = BillerDefaultState, action) => {
    switch (action.type) {
    case "ADD_BILLER":
     return [...state, action.biller];
     default:
      return state;
     }
     };
     export default billerReducer;

Solution

  • It looks like it's the way Thunk is initialized into the store - the enhancer should be the third argument.

    From the docs

    createStore(reducer, [preloadedState], [enhancer])

    [enhancer] (Function): The store enhancer. You may optionally specify it to enhance the store with third-party capabilities such as middleware, time travel, persistence, etc. The only store enhancer that ships with Redux is applyMiddleware().

    Here's how I initialize it in my project, noting that I've imported the reducers object in a similar way that you've defined it in your code:

    import { createStore, applyMiddleware, compose } from 'redux'
    import reduxThunk from 'redux-thunk'
    
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
    const store = createStore(reducers, {}, composeEnhancers(
      applyMiddleware(reduxThunk)
    ))
    

    Note that I've also added in Redux Devtools, though if you don't want this additional functionality, you can just stick to compose, or applyMiddleware on its own if there's nothing to compose.