React / Redux:错误:操作必须是普通对象。使用自定义中间件进行异步操作

时间:2018-08-27 20:10:47

标签: javascript reactjs asynchronous redux

这是我的组件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();

请注意,我之前已经做过一些研究,以找出可能导致这种错误的根本原因,并且看来它可能源于多种原因。我检查了发现的内容,但没有帮助。

3 个答案:

答案 0 :(得分:2)

返回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进行了测试。

答案 1 :(得分:1)

这是在the React-Redux issues list上发布的,我在那里回答了。为了完整起见,我将粘贴我的解决方案。

首先,根本问题是,不是普通动作对象的东西正在到达实际的商店。您可以在Redux源代码的dispatch函数中放置一个断点,以查看实际值(或在项目的node_modules文件夹中编辑Redux的副本以添加一些日志记录)。

实际上,我认为我看到了问题。真正的问题是,您要将两个单独的商店增强器传递给createStore。一个是applyMiddleware的中间件增强器,另一个是Redux DevTools扩展。您需要将它们“一起”组合成一个组合的增强器。有关如何正确执行此操作的可复制粘贴示例,请参见Redux文档中的Configuring Your Store页。

另外两个建议:

您可以使用“对象简写”来代替手动编写mapDispatch函数,而只需将充满动作创建者的对象直接传递给connect。您已经有了import * as actionCreators语句中充满动作创建者的对象,因此您可以这样做:export default connect(mapState, actionCreators)(UserHandler)。 (也就是说,函数名称与所需的prop名称不同,因此您可能需要创建一个新对象,例如{onUserSelection : actionCreators.fetchSelectedUser}并传递该对象。)

此外,我们正在使用的redux-starter-kit package具有一个为您设置商店的功能,并自动添加redux-thunk和DevTools扩展。您可能要尝试使用它而不是自己设置商店。

答案 2 :(得分:0)

问题是,您正在调用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),
});

现在您已经将调度功能绑定到了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)),
                );
        });
};