Can't fix error: Actions must be plain objects. Instead, the actual type was: 'function'

Can't fix error: Actions must be plain objects. Instead, the actual type was: 'function'

几天来我一直在尝试解决这个问题,在 SO 上阅读了类似的问题,但仍然找不到问题所在。

对于特定操作,我收到以下错误:Actions must be plain objects. Instead, the actual type was: 'function' 但问题是:它适用于某些功能但不适用于其他功能。

为了简洁省略了一些代码。

工作示例(onGetConnectors()

在这里,调用 actions.onGetConnectors() 工作正常,我收到来自状态更新的 connectors

CardDetail/index.js

const BoardDetailView = (props) => {
  const {boardDetail, connectors, actions} = props;

  const getBoardData = useCallback(() => {
    if (boardDetail) {
      console.log('[BoardDetailView] Board detail:', boardDetail);
      actions.onGetConnectors(); // This works fine
      return {
        ...boardDetail,
        lanes: boardDetail.lanes || [], // if empty, add at least one lane
      };
    }
  }, [boardDetail]);

  const [boardData, setBoardData] = useState(getBoardData());

  return (
    <AppsContent
      <Board
        data={boardData}
        onDataChange={shouldReceiveNewData}
        components={{
          BoardWrapper: BoardWrapper,
          Card: CardDetail,
          LaneHeader: ListHeader,
          AddCardLink: AddCardButton,
          NewCardForm: CardDrawer,
          NewLaneForm: AddNewList,
          NewLaneSection: NewListButton,
        }}
      />
      <CardDrawer open={addCardOpen} onCloseCard={onCloseCard} selectedLane={selectedLane} board={boardDetail} selectedCard={selectedCard} setSelectedCard={setSelectedCard} connectors={connectors} />
    </AppsContent>
  );
};

BoardDetailView.propTypes = {
  boardDetail: PropTypes.object,
  connectors: PropTypes.array,
  actions: PropTypes.object,
};

function mapStateToProps(state) {
  return {
    connectors: state.connectors.connectors,
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: {
      onGetConnectors: bindActionCreators(appGlobalActions.onGetConnectors, dispatch),
    },
  };
}

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

redux/actios/Connectors.js

export const onGetConnectors = () => {
  const {messages} = appIntl();

  // ERROR DOES NOT OCCUR FOR THIS FUNCTION

  return (dispatch) => {
    dispatch({type: FETCH_START});

    jwtAxios
      .get('/connectors/')
      .then((data) => {
        if (data.status === 200) {
          dispatch({type: FETCH_SUCCESS});
          dispatch({type: GET_CONNECTORS, payload: data.data});
        } else {
          dispatch({
            type: FETCH_ERROR,
            payload: messages['message.somethingWentWrong'],
          });
        }
      })
      .catch((error) => {
        dispatch({type: FETCH_ERROR, payload: error.message});
      });
  };
};

export const onGetAccounts = (accessId) => {
  const {messages} = appIntl();

  // ERROR OCCURS HERE <------------------

  return (dispatch) => {
    dispatch({type: FETCH_START});

    jwtAxios
      .get(`/accounts/?accessId=${accessId}`)
      .then((data) => {
        if (data.status === 200) {
          console.log('data:', data);
          dispatch({type: FETCH_SUCCESS});
          dispatch({type: GET_ACCOUNTS, payload: data.data});
          dispatch({
            type: SHOW_MESSAGE,
            payload: messages['message.accountsRetrieved'],
          });
        } else {
          dispatch({
            type: FETCH_ERROR,
            payload: messages['message.somethingWentWrong'],
          });
        }
      })
      .catch((error) => {
        dispatch({type: FETCH_ERROR, payload: error.message});
      });
  };
};

在下一个例子中使用了getAccounts(),它抛出以下错误:

Uncaught Error: Actions must be plain objects. Instead, the actual type was: 'function'. You may need to add middleware to your store setup to handle dispatching other values, such as 'redux-thunk' to handle dispatching functions.

这是我的 redux 商店,显示我已经在使用 redux-thunk

import {applyMiddleware, compose, createStore} from 'redux';
import reducers from '../reducers';
import {routerMiddleware} from 'connected-react-router';
import thunk from 'redux-thunk';

const createBrowserHistory = require('history').createBrowserHistory;
const history = createBrowserHistory();
const routeMiddleware = routerMiddleware(history);

const middlewares = [thunk, routeMiddleware];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default function configureStore(initialState) {
  const store = createStore(reducers(history), initialState, composeEnhancers(applyMiddleware(...middlewares)));

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers/index', () => {
      const nextRootReducer = require('../reducers');
      store.replaceReducer(nextRootReducer);
    });
  }

  return store;
}
export {history};

失败示例 (onGetAccounts())

此处,从 useEffectonRefreshButtonClick() 函数调用 onGetAccounts() 时会抛出错误。

const CardDetail = (props) => {
  const {title, access, attachments, label, refreshedAccounts, date, comments, onClick, editable, actions} = props;

  useEffect(() => {
    if (access) {
      console.log('[CardDetail] Getting accounts for access id:', access.id);
      actions.onGetAccounts(access.id);
    }
  }, [access]);

  const renderAccountData = (account) => {
    let displayData = {
      uniqueKey: '',
      label: '',
      value: '',
    };

    switch (account.vendorId) {
      case 'bank':
        displayData.uniqueKey = account.vendorAccountId;
        displayData.label = account.asset;
        displayData.value = `${account.balance}`;
        break;
      }
    }

    return (
      <Box key={displayData.uniqueKey}>
        <Box component='div'>
          {displayData.label}
        </Box>
        <Box component='div'>
          {displayData.value}
        </Box>
      </Box>
    );
  };

  const onRefreshButtonClick = async (e) => {
    e.stopPropagation();
    console.log('[CardDetail] Refreshing accounts for access:', access);
    actions.onGetAccounts(access.id);
  };

  return (
    <Card
      <Box
        onClick={(e) => {
          e.stopPropagation();
          onClick(e);
        }}>
        {/* Accounts */}
        <Box>
          {refreshedAccounts?.map((account) => {
            renderAccountData(account);
          })}
        </Box>
      </Box>
    </Card>
  );
};

CardDetail.defaultProps = {
  attachments: [],
  accounts: [],
  config: {},
  label: [],
};

CardDetail.propTypes = {
  title: PropTypes.string,
  attachments: PropTypes.array,
  label: PropTypes.array,
  refreshedAccounts: PropTypes.array,
  access: PropTypes.object,
  date: PropTypes.string,
  comments: PropTypes.array,
  onClick: PropTypes.func,
  editable: PropTypes.bool,
  actions: PropTypes.object,
};

function mapStateToProps(state) {
  return {
    refreshedAccounts: state.connectors?.accounts,
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: {
      onGetAccounts: bindActionCreators(appGlobalActions.onGetAccounts, dispatch),
    },
  };
}

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

如果能帮助解决问题,我们将不胜感激。我不知所措地试图理解为什么 onGetConnectors() 有效但 onGetAccounts().

原来问题出在我共享的代码之外。

这是由于 react-trelloCard 组件中调用 API 时导致此问题。