簡體   English   中英

React / Redux:錯誤:操作必須是普通對象。 使用自定義中間件進行異步操作

[英]React/Redux: Error: Actions must be plain objects. Use custom middleware for async actions

這是我的組件UserHandler的代碼

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import * as actionCreators from '../../store/actions/actions';

class UserHandler extends Component {
  componentDidMount() {
    const { onInitUsers } = this.props;
    onInitUsers();
  }

  render() {
    // some code
    return (          
        {/* SOME JSX */}
    );
  }
}

const mapStateToProps = state => ({
  //    state to props mapping
});

const mapDispatchToProps = dispatch => ({
  onUserEdition: username => dispatch(actionCreators.editUser(username)),
  onUserSelection: username => dispatch(actionCreators.fetchSelectedUser(username)),
  onInitUsers: () => dispatch(actionCreators.initUsers()),
});

// PropTypes definition and defaultProps

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

在我的actionCreators文件中,這是我定義的內容:

const initUsersStart = createAction(INIT_USERS_START);
const setUsers = createAction(SET_USERS, users => ({ users }));
const initUsersError = createAction(INIT_USERS_ERROR, error => ({ error }));


const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return axios.get('/users')
    .then(
      response => dispatch(setUsers(response.data)),
    )
    .catch(
      error => dispatch(initUsersError(error)),
    );
};

當我評論onInitUsers(); 調用componentDidMount()函數后,我不再遇到該錯誤。 我想了解為什么這會引發此錯誤。

最后,這是我創建store

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

import App from './App';
import registerServiceWorker from './registerServiceWorker';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import reducer from './store/reducers/reducers';

const store = createStore(
  reducer, /* preloadedState, */
  applyMiddleware(thunk),
  /* eslint-disable no-undef */ /* eslint-disable no-underscore-dangle */
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  /* eslint-enable */
);

// const store = createStore(reducer);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  /* eslint-disable no-undef */
  document.getElementById('root'),
  /* eslint-enable */
);
registerServiceWorker();

請注意,我之前已經做過一些研究,以找出可能導致這種錯誤的根本原因,而且看來它可能源於多種原因。 我檢查了發現的內容,但沒有幫助。

返回axios調用,因此無論邏輯遵循哪種路徑,Redux都會根據需要返回一個對象。

const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return axios.get('/users')
    .then(
      response => dispatch(setUsers(response.data)),
    )
    .catch(
      error => dispatch(initUsersError(error)),
    );
};

測試完代碼后,我認為問題還在於商店配置。 中間件應作為createStore函數的最后一個參數應用:

const store = createStore(
  reducer, /* preloadedState, */
  /* eslint-disable no-undef */ /* eslint-disable no-underscore-dangle */
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  /* eslint-enable */
  applyMiddleware(thunk),
);

我使用redux v.4.0.0和react-redux v.5.0.7進行了測試。

這已發布在React-Redux問題列表中 ,我在那里回答了。 為了完整起見,我將在這里粘貼我的解決方案。

首先,根本問題是,不是普通動作對象的東西正在到達實際的商店。 您可以在Redux源代碼的dispatch函數中放置一個斷點,以查看實際值(或在項目的node_modules文件夾中編輯Redux的副本以添加一些日志記錄)。

實際上,我認為我看到了問題。 真正的問題是,您要將兩個單獨的商店增強器傳遞給createStore 一個是applyMiddleware的中間件增強器,另一個是Redux DevTools擴展。 您需要將它們“一起”組合成一個組合的增強器。 有關如何正確執行此操作的可復制粘貼示例,請參見Redux文檔中的“ 配置商店”頁面。

另外兩個建議:

您可以使用“對象簡寫”來代替手工編寫mapDispatch函數,而只需將充滿動作創建者的對象直接傳遞給connect 您已經具有來自import * as actionCreators語句的充滿動作創建者的對象,因此您可以執行以下操作: export default connect(mapState, actionCreators)(UserHandler) (也就是說,函數名稱與所需的prop名稱不同,因此您可能需要創建一個新對象,例如{onUserSelection : actionCreators.fetchSelectedUser}然后傳遞該對象。)

此外,我們還有一個正在使用的redux-starter-kit軟件包 ,該軟件包具有一個為您設置商店的功能,並且會自動添加redux-thunk和DevTools擴展。 您可能要嘗試使用它而不是自己設置商店。

問題在於,您正在通過調用onInitUsers()來分派操作,因為它位於dispatch()函數內部。 如果調度一個動作,則需要返回一個具有鍵type和可選負載的對象。

您需要的是bindActionCreators內部的mapDispatchToProps函數,如下所示:

import { bindActionCreators } from "redux";

const mapDispatchToProps = dispatch => ({
  onUserEdition: username => dispatch(actionCreators.editUser(username)),
  onUserSelection: username => dispatch(actionCreators.fetchSelectedUser(username)),
  onInitUsers: bindActionCreators(actionCreators.initUsers, dispatch),
});

現在,您已將dispatch函數綁定到您的initUsers函數,可以像我們想要的那樣使用它。


編輯:嘗試將您的onInitUser函數更改為以下內容:

const initUsers = () => (dispatch) => {
  dispatch(initUsersStart());
  return dispatch({
            type: 'GET_USER',
            payload: axios.get('/users')
                .then(
                  response => dispatch(setUsers(response.data)),
                )
                .catch(
                  error => dispatch(initUsersError(error)),
                );
        });
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM