使用 redux-thunk 时动作必须是普通对象

Actions must be plain objects while using redux-thunk

我正在使用 react-redux 和 redux-thunk 实现异步操作创建器。但是,我收到以下错误消息:未捕获错误:操作必须是普通对象。使用自定义中间件进行异步操作。

我知道动作应该是普通对象,像 thunk 这样的中间件应该处理它们不是的情况。我已经阅读了几个教程并查看了 every SO question I could find on this,但我仍然无法弄清楚我哪里出错了。我是否错误地设置了 thunk,或者我是否以错误的方式使用了 action creators?这可能是 webpack 或其他错误?

下面包含了我认为相关的代码片段。如果需要其他信息,请告诉我。

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
}

相关片段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);

在此先感谢您的帮助!

我怀疑这可能是因为你有一个 async (dispatch) 函数。这将导致它 return 变成 Promise,甚至可能令人困惑 thunk

在正常情况下,函数本身会 return 另一个函数,thunk 会注入 dispatch 并再次调用,你会在函数内部调用 dispatch :

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

加上async,基本上就变成这样了:

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

您可能不得不放弃其中的 async/await 并仅使用 axios 作为正常的 Promise,或者添加一些额外的东西以确保它 return 什么都不是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'}))
  }
 }
}

正在返回一个承诺,所以当你这样做时

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

dispatch(fetchPrices()) 得到的不是 普通 对象

的承诺

我做这些事情的方式是把重量留给我的行动;调用异步,当解决调度数据存储和在你的组件中监听和处理数据(价格列表)变化。

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

因此您可以显示 "loading please wait" 而价目表为空且承诺不是 resolved/rejected

以防有人遇到同样的问题。问题不在上面显示的代码中,也不在我如何调度操作中。我在另一个文件中有 redux-store 的重复定义,它用中间件覆盖了定义。

如果有人在使用 ImmutableJS + Typescript 时遇到麻烦,结果是您必须定义 "initialState" 中间件才能实际应用。

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

在我的例子中,我有如下的动作声明,因此它抛出了这样的错误。

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

我所做的只是将我的动作定义更改为对象类型

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

而且效果很好!