尝试使用API创建简单的CRUD应用。我已经可以使用登录和注册了,所以我知道在商店中正确设置了redux-thunk。
我已经看到很多类似的问题,但是没有一个答案可以解决我的问题。我知道调度应该返回函数。我很确定是这样。我是新来的反应者,对如何调试有些迷茫。 Console.log没有显示任何内容,因此我使用了警报。很高兴提供任何其他信息。谢谢。
错误
Error: Actions must be plain objects. Use custom middleware for async actions.
20 | componentDidMount() {
21 | const { dispatch } = this.props;
22 | const { error, rosterMembers, isFetching } = this.props;
23 | dispatch(rosterActions.getAll());
24 |
25 | }
26 |
容器:RosterListCard.js
import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {Card, CardBody, Col, ButtonToolbar} from 'reactstrap';
import EmailIcon from 'mdi-react/EmailIcon'
import CheckboxMarkedCircleIcon from 'mdi-react/CheckboxMarkedCircleIcon'
import AlertCircleIcon from 'mdi-react/AlertCircleIcon'
import {Link} from 'react-router-dom';
import { Table } from 'reactstrap';
import { rosterActions } from '../../../../redux/actions';
class RosterListCard extends PureComponent {
constructor(props) {
super(props);
// this.getNoRowsRenderer = this.getNoRowsRenderer.bind(this);
// this.getRowClassName = this.getRowClassName.bind(this);
}
componentDidMount() {
const { dispatch } = this.props;
const { error, rosterMembers, isFetching } = this.props;
dispatch(rosterActions.getAll());
}
componentWillReceiveProps(nextProps) {
const { dispatch } = nextProps;
dispatch(rosterActions.getAll());
}
getNoRowsRenderer() {
return (
<div className="noRows">
No rows
</div>
);
}
render() {
const { error, rosterMembers, isFetching } = this.props;
return (
<div className="container">
{console.log(error)}
{console.log(isFetching)}
{console.log(rosterMembers)}
{error &&
<div className="alert alert-danger">
{error.message || "Unknown errors."}
</div>}
{!isFetching &&
rosterMembers.length === 0 &&
<div className="alert alert-warning">Oops, nothing to show.</div>}
{rosterMembers &&
<Table striped>
<thead>
<tr>
<th>Name</th>
<th>Title</th>
</tr>
</thead>
<tbody>
{this.props.rosterMembers.map((rosterMember) => (
<tr>
<th scope="row">{rosterMember.fullName}</th>
<td>{rosterMembers.title}</td>
</tr>
))}
</tbody>
</Table>
}
</div>
)
}
}
RosterListCard.propTypes = {
rosterMembers: PropTypes.array.isRequired,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
dispatch: PropTypes.func.isRequired
};
function mapStateToProps (state) {
return {
error: null,
isFetching: false,
didInvalidate: false,
totalCount: 0,
rosterMembers: []
};
}
export default connect(mapStateToProps)(RosterListCard);
动作:roster.actions.js
import { sessionService } from 'redux-react-session';
import { rosterConstants } from '../constants';
import { callApi } from "../../utilities/api.utility.js";
export const rosterActions = {
getAll
};
function rosterRequest() {
return {
type: rosterConstants.GETALL_REQUEST
};
}
function rosterSuccess() {
return function(payload) {
return {
type: rosterConstants.GETALL_SUCCESS,
rosterMembers: payload.items,
totalCount: payload.total_count
};
};
}
function rosterFailure() {
return function(error) {
return {
type: rosterConstants.GETALL_FAILURE,
error
};
};
}
export function getAll() {
sessionService.loadSession()
.then(session => {
// if (typeof session.token === 'undefined') return rosterFailure();
const url = `${process.env.REACT_APP_API_BASE_URL}/Rosters?access_token=${session.token}`;
return callApi(
url,
null,
rosterRequest(),
rosterSuccess(),
rosterFailure()
)
});
}
API模块:api.utility.js
import "isomorphic-fetch";
export function checkStatus(response) {
if (!response.ok) {
// (response.status < 200 || response.status > 300)
const error = new Error(response.statusText);
error.response = response;
throw error;
}
return response;
}
export function parseJSON(response) {
return response.json();
}
/**
* A utility to call a restful service.
*
* @param url The restful service end point.
* @param config The config object of the call. Can be null.
* @param request The request action.
* @param onRequestSuccess The callback function to create request success action.
* The function expects response json payload as its argument.
* @param onRequestFailure The callback function to create request failure action.
* The function expects error as its argument.
*/
export function callApi(
url,
config,
request,
onRequestSuccess,
onRequestFailure
) {
alert('request');
return dispatch => {
alert('request***');
dispatch(request);
return fetch(url, config)
.then(checkStatus)
.then(parseJSON)
.then(json => {
alert('request***');
dispatch(onRequestSuccess(json));
})
.catch(error => {
alert('request***');
const response = error.response;
if (response === undefined) {
dispatch(onRequestFailure(error));
} else {
error.status = response.status;
error.statusText = response.statusText;
response.text().then(text => {
try {
const json = JSON.parse(text);
error.message = json.message;
} catch (ex) {
error.message = text;
}
dispatch(onRequestFailure(error));
});
}
});
};
alert('request end');
}
答案 0 :(得分:0)
如果您使用的是redux-thunk
,那么您的异步“动作创建者”应该类似于:
export function getAll() {
return dispatch => {
sessionService.loadSession()
.then(session => {
if (typeof session.token === 'undefined') return dispatch(rosterFailure());
const url = `${process.env.REACT_APP_API_BASE_URL}/Rosters?access_token=${session.token}`;
dispatch(rosterRequest());
fetch(url, config).then(response => {
// validate response and convert to JSON
dispatch(rosterSuccess(json));
}
}).catch(err => {
// Handle/Transform error
dispatch(rosterFailure(err));
}
});
}
}
此外,我认为您缺少有关redux-thunk
的一些详细信息。异步dispatch
其他动作的动作应返回函数(其中dispatch
是第一个也是唯一的必需参数)。其他动作应该只返回带有type
的典型动作对象以及化简函数更新其存储所需要的其他信息。
例如,您的rosterRequest
看起来完全符合我的期望,但是rosterSuccess
应该看起来像这样:
function rosterSuccess(paylod) {
return {
type: rosterConstants.GETALL_SUCCESS,
rosterMembers: payload.items,
totalCount: payload.total_count
};
}
然后,您在mapDispatchToProps
组件时可以connect
,而不希望组件直接具有dispatch
道具。
例如,在RosterListCard.js
的底部:
RosterListCard.propTypes = {
rosterMembers: PropTypes.array.isRequired,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
getAllRoster: PropTypes.func.isRequired
};
function mapStateToProps (state) {
return {
error: null,
isFetching: false,
didInvalidate: false,
totalCount: 0,
rosterMembers: []
};
}
function mapDispatchToProps(dispatch) {
return {
getAllRoster: rosterActions.getAll
}
}
export default connect(mapStateToProps, mapDispatchToProps)(RosterListCard);
只要需要,您就可以从this.props
调用该函数:
componentDidMount() {
const { error, rosterMembers, isFetching } = this.props;
this.props.getAllRoster();
}