Search code examples
javascriptreactjsreact-reduxredux-thunk

Actions must be plain objects while using redux-thunk


I am implementing asynchronous action creators using react-redux and redux-thunk. However, I am getting the following error message: Uncaught Error: Actions must be plain objects. Use custom middleware for async actions.

I know that actions are supposed to be plain objects, and that middleware like thunk is supposed to take care of the cases when they are not. I have read several tutorials and looked at every SO question I could find on this, but I still can't figure out where I'm going wrong. Am I setting up thunk incorrectly, or am I using action creators in a bad way? Might this be an error with webpack or something?

Below I've included the code snippets I believe are relevant. Please let me know if additional info is needed.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Route } from 'react-router';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';

import rootReducer   from './reducers';
import Layout    from './components/Layout.js';
import OrderPage from './containers/order-page';


const store = createStore(
    rootReducer,
    applyMiddleware(thunk)
    );

ReactDOM.render(
    <Provider store={store}>
        <App>
            <Route  exact path="/" component={Layout}/>
        </App>
    </Provider>,
    document.querySelector('.app'));

reducers/order.js

import { FETCH_ERR, FETCH_SUCCESS, START_FETCH } from '../actions/types';

const initialState = {
  fetching: false
};

export default (state=initialState, action)=>{
  switch (action.type) {
    case START_FETCH: 
      return {
        fetching: true
      }
    case FETCH_ERR:
      return {
        err: action.payload.err,
        fetching: false
      }
    case FETCH_SUCCESS:
      return {
        price: action.payload,
        fetching: false
      }
    default:
        return state
  }

}

actions/price-fetch.js

import axios from 'axios'

const FETCH_ERR = 'FETCH_ERR'
const FETCH_SUCCESS = 'FETCH_SUCCESS'
const START_FETCH  = 'START_FETCH'


const fetchSucc = (data)=>{
  return{
    type:FETCH_SUCCESS,
    payload:data
  }
}

const fetchFail = (message)=>{
  return{
    type:FETCH_ERR,
    payload:message
  }
}

const startFetch = () =>{
  return{
    type: START_FETCH,
    payload:null
  }
}

const fetchPrices = () =>{
  return async (dispatch) =>{
    try {
      dispatch(startFetch())
      let data = await axios.get('mybackendurl')
      dispatch(fetchSucc(data))
    } catch (error) {
      dispatch(fetchFail({err:'failed to get shit'}))
    }
  }
}

export {
    FETCH_ERR,
    FETCH_SUCCESS,
    fetchPrices,
    START_FETCH
}

Relevant pieces of containers/order.js

import React, { Component }     from 'react';

import { connect }                      from 'react-redux';

import { fetchPrices }          from '../actions/price-fetch';

class Order extends Component {


...



  render() {
    this.props.fetchPrices();
    return ...

  }


const mapDispatchToProps = dispatch => {
  return {
    fetchPrice: () => {
      dispatch(fetchPrices())
    }
  }
}

function mapStateToProps(state){
    return {
        prices: state.order
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Order);

Thanks in advance for any help!


Solution

  • In case anyone comes across the same issue. The problem was not in the code shown above, or how I was dispatching actions. I had a duplicate definition of the redux-store in a different file, which overwrote the definition with the middleware.