Reactjs 在React中使用Redux和Redux Thunk处理失败的Ajax调用
对于我的React组件,我使用Redux(React-Redux)和Redux-Thunk来维护应用程序状态 有一个Reactjs 在React中使用Redux和Redux Thunk处理失败的Ajax调用,reactjs,redux,react-redux,Reactjs,Redux,React Redux,对于我的React组件,我使用Redux(React-Redux)和Redux-Thunk来维护应用程序状态 有一个ShowGroup组件从后端检索group。如果组不存在(或在任何其他错误情况下),将调用错误回调来更新状态 class ShowGroup extends Component { constructor(props) { super(props); this.groupId = this.props.match.params.id; this.stat
ShowGroup
组件从后端检索group
。如果组不存在(或在任何其他错误情况下),将调用错误回调来更新状态
class ShowGroup extends Component {
constructor(props) {
super(props);
this.groupId = this.props.match.params.id;
this.state = {
'loaded': false,
'error': null
};
}
_fetchGroupErrorCallback = response => {
this.setState({loaded: true, error: response});
}
componentDidMount() {
this.props.fetchGroup(this.groupId, this._fetchGroupErrorCallback);
}
render() {
//what is the best practice here ?
let group = this.props.groups[this.groupId];
if (!group) {
if (!this.state.loaded) {
return <div>Loading group ....</div>;
}
if (this.state.error) {
return <div>{this.state.error.data.message}</div>;
}
}
return (
<div className="show-group">
<form>
{_.map(FIELDS, renderField.bind(this))}
</form>
</div>
);
}
}
function mapStateToProps(state) {
return { groups: state.groups };
}
const mapDispatchToProps = (dispatch) => {
return {
fetchGroup: (id, callback) => dispatch(fetchGroup(id, callback)),
updateGroup: (id) => dispatch(updateGroup(id))
};
};
export default reduxForm({
validate,
//a unique id for this form
form:'ShowGroup',
fields: _.keys(FIELDS),
fields_def: FIELDS
})(
connect(mapStateToProps, mapDispatchToProps)(ShowGroup)
);
groupFetchedErrored
操作创建者:
export function groupFetchErrored(response) {
//handle the error here
return {
type: FETCH_GROUP_ERROR,
response
}
}
和减速器:
export default function(state=INITIAL_STATE, action) {
switch(action.type) {
//....
case FETCH_GROUP_ERROR:
return _.omit(state, action.response.data.id);
default:
return state;
}
}
const rootReducer = combineReducers({
form: formReducer,
groups: groupReducer
});
export default rootReducer;
问题:
A.如果出现错误响应,组件将渲染三次:
1.第一次加载时(在进行ajax调用之后)
2. <代码>\u fetchGroupErrorCallback被调用,并且状态被设置,这将导致渲染
3. groupFetchErrored
被调度,导致另一个渲染
B.如果响应成功,组件会被渲染两次,但状态不正确,因为没有任何东西会更新它(我认为为它添加回调是不正确的)
在使用React的Redux和Redux Thunk时,处理ajax错误响应的最佳实践是什么?action creator和reducer应该如何通知组件有问题
更新1
这是我的根减速机:
export default function(state=INITIAL_STATE, action) {
switch(action.type) {
//....
case FETCH_GROUP_ERROR:
return _.omit(state, action.response.data.id);
default:
return state;
}
}
const rootReducer = combineReducers({
form: formReducer,
groups: groupReducer
});
export default rootReducer;
如您所见,我有组
,这是一个形式对象:
{
groupId1: groupData1,
groupId2, groupData2,
....
}
所以,另一个问题是,我应该如何指定一个组正在加载(我不能在
组
级别上进行isLoading
或errorFetching
,为每个无效的组id用户添加一个条目似乎不是一个好主意。或者可能有一种方法可以将无效的组id放入映射中,然后将其清除?不过,我不知道应该在哪里发生这种情况。将所有状态放入与提取相关的数据进入Redux存储。然后该存储成为您唯一的真相来源
然后可以完全省略fetchErrorCallback
您的减速器中已经有一个位置将收到错误通知:
case FETCH_GROUP_ERROR:
return _.omit(state, action.response.data.id);
您可以将错误存储在redux状态:
case FETCH_GROUP_ERROR:
const stateWithoutId = _.omit(state, action.response.data.id);
return {
...stateWithoutId,
errorFetching: action.response.error,
isLoading: false
}
然后通过mapstatetops
将errorFetching
和isLoading
传递到组件中,就像您已经对组所做的那样
此外,为了正确跟踪isLoading
,最好在开始提取时(就在调用axios.get
之前)分派另一个操作,可能fetch\u组\u已启动
。然后在调度该操作类型时,在减速机中将isLoading
设置为true
case GROUP_FETCHED:
return {
...state,
isLoading: false,
group: action.response.data // or however you're doing this now.
};
case FETCH_GROUP_STARTED:
return { ...state, isLoading: true }; // or maybe isFetchingGroups is a better name
如果这是我的代码,我会做另一个更改:我不会将响应
传递给动作创建者,而是将相关数据剥离出来并传递给他们。因此,reducer不需要知道如何处理响应
对象;它只接收显示组件所需的数据正确。这样,所有处理axios调用并必须知道它们返回的对象的形状的代码都在一个地方—操作函数。类似于:
动作创造者
行动
减速器
您可能已经注意到我在上面的action creators中使用了action.payload
通常的做法是在分派的操作上始终使用相同的名称作为数据属性(就像始终在整个应用程序的每个reducer和每个action creator中一样)。这样,reducer就不需要与action creator紧密耦合;它知道数据总是在有效负载字段中。(也许这就是您使用响应所做的,但它似乎专门用于http响应。)
将与获取相关的所有状态数据放入Redux存储。然后该存储成为您的唯一真相来源
然后可以完全省略fetchErrorCallback
您的减速器中已经有一个位置将收到错误通知:
case FETCH_GROUP_ERROR:
return _.omit(state, action.response.data.id);
您可以将错误存储在redux状态:
case FETCH_GROUP_ERROR:
const stateWithoutId = _.omit(state, action.response.data.id);
return {
...stateWithoutId,
errorFetching: action.response.error,
isLoading: false
}
然后通过mapstatetops
将errorFetching
和isLoading
传递到组件中,就像您已经对组所做的那样
此外,为了正确跟踪isLoading
,最好在开始提取时(就在调用axios.get
之前)分派另一个操作,可能fetch\u组\u已启动
。然后在调度该操作类型时,在减速机中将isLoading
设置为true
case GROUP_FETCHED:
return {
...state,
isLoading: false,
group: action.response.data // or however you're doing this now.
};
case FETCH_GROUP_STARTED:
return { ...state, isLoading: true }; // or maybe isFetchingGroups is a better name
如果这是我的代码,我会做另一个更改:我不会将响应
传递给动作创建者,而是将相关数据剥离出来并传递给他们。因此,reducer不需要知道如何处理响应
对象;它只接收显示组件所需的数据正确。这样,所有处理axios调用并必须知道它们返回的对象的形状的代码都在一个地方—操作函数。类似于:
动作创造者
行动
减速器
您可能已经注意到我在上面的action creators中使用了action.payload
通常的做法是在分派的操作上始终使用相同的名称作为数据属性(就像始终在整个应用程序的每个reducer和每个action creator中一样)。这样,reducer就不需要与action creator紧密耦合;它知道数据总是在有效负载字段中。(也许这就是您使用响应所做的,但它似乎专门用于http响应。)
为什么要同时使用状态和道具?让道具成为唯一的真相来源,不要使用状态。这听起来不错,但是fetchGroup
应该如何告诉组件服务器响应了错误?为什么要同时使用状态和道具?让道具成为唯一的真相来源,不要使用状态