![](/img/trans.png)
[英]Error: Actions must be plain objects. Use custom middleware for async actions. React-redux error
[英]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.