javascript - Actions must be plain objects while using redux-thunk - Stack Overflow

I am implementing asynchronous action creators using react-redux and redux-thunk. However, I am getting

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 './ponents/Layout.js';
import OrderPage from './containers/order-page';


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

ReactDOM.render(
    <Provider store={store}>
        <App>
            <Route  exact path="/" ponent={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!

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 './ponents/Layout.js';
import OrderPage from './containers/order-page';


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

ReactDOM.render(
    <Provider store={store}>
        <App>
            <Route  exact path="/" ponent={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!

Share Improve this question asked Jan 29, 2018 at 21:13 maalandmaaland 4561 gold badge5 silver badges15 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 2

In case anyone es 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.

In my case, I had the action declaration like below, due to which it was throwing such error.

export const withdrawMoney = (amount) => {
return (dispath) => {
    dispath({
        type: "withdraw",
        payload: amount
    })
}};

What I did was just changed my action definition to be an object type

export const depositMoney = (amount) => ({
   type: "deposit",
   payload: amount
});

And it jsut worked fine!

If anyone is here grasping at straws when using ImmutableJS + Typescript, turns out that you HAVE to define the "initialState" for the middleware to actually apply.

export const store = createStore(
  bineReducers({APIReducer}),
  {},
  applyMiddleware(thunk.withExtraArgument(api))
);

I suspect it may be because you have an async (dispatch) function. That would cause it to return a Promise, which may be even confusing thunk.

In normal scenarios, the function itself would return another function, which thunk would inject the dispatch and call again and you would call dispatch inside the function:

arg => dispatch => dispatch({ type: arg });

When you add async, it basically bees the same as this:

arg => dispatch => Promise.resolve(dispatch({ type: arg }));

You may have to ditch async/await inside of there and just use axios as a normal Promise, or add something extra to ensure it returns a nothing instead of a Promise.

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'}))
  }
 }
}

is returning a promise so when you do

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

dispatch(fetchPrices()) is getting a promise not a plain object

the way i do these things is leave the heavy weight to my action; call async, when resolved dispatch data to store and in your ponent listen for and handle data(prices list) change.

const mapDispatchToProps = dispatch => {
  return {
    fetchPrice
  }
}

you can thus show "loading please wait" while price list is empty and promise is not resolved/rejected

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745298542a4621293.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信