Reactjs 在react redux应用程序中处理请求呼叫响应以避免使用回调
这是一个设计问题,但我想知道是否有处理这种情况的最佳实践 我有一个react redux应用程序。应用程序状态结构如下所示:Reactjs 在react redux应用程序中处理请求呼叫响应以避免使用回调,reactjs,redux,Reactjs,Redux,这是一个设计问题,但我想知道是否有处理这种情况的最佳实践 我有一个react redux应用程序。应用程序状态结构如下所示: { groups: {gid1: group1, gid2: group2, ....}, expenses: {eid1: expense1, eid2: expense2, ...}, //.... the rest } NewGroup组件旨在创建一个新组。如果对后端的createrequestajax请求成功,它将被添加到app状态下的组列表
{
groups: {gid1: group1, gid2: group2, ....},
expenses: {eid1: expense1, eid2: expense2, ...},
//.... the rest
}
NewGroup组件旨在创建一个新组。如果对后端的createrequestajax请求成功,它将被添加到app状态下的组列表中。新组是一个模式,将关闭,组列表将更新
但是,如果请求未成功,则不应关闭NewGroup组件
主要问题是:如果请求成功或不成功,我是否应该在应用程序状态中包含请求状态、后一种情况下的错误消息、是否返回结果等?这就是我真正怀疑的地方,因为它使应用程序状态非常丑陋、庞大,在某些情况下,它无法处理某些情况,在这种情况下:创建一个新组
假设我将响应状态代码和错误消息添加到应用程序状态:
{
groups: {
newGroupId1: {
data: newGroupData1,// null in case it was not successful
isLoading: true/false, // if the call is returned or not
errorFetching: message1
}
}
}
在对后端的第二个不成功的create请求中,无法区分以前的调用和当前调用,因为它们都具有ERRORFFETCHING和类似的isLoading值。例如,两者都没有为errorFetching找到组,为isLoading找到false
当使用redux时,区分请求调用的状态和应用程序状态中的真实数据的最佳实践是什么
更新1
这是减速器:
import { FETCH_GROUPS_SUCCESS, FETCH_GROUPS_ERROR, CREATE_GROUP_SUCCESS, CREATE_GROUP_ERROR, DELETE_GROUP, FETCH_GROUP_SUCCESS, FETCH_GROUP_ERROR } from '../actions/creators';
export const FULL_GROUP = 'full_group';
export const SNIPPET_GROUP = 'snippet_group';
const INITIAL_STATE = {
data: null,
isLoading: true,
errorFetching: null
};
export default function(state=INITIAL_STATE, action) {
switch(action.type) {
case FETCH_GROUPS_SUCCESS:
return {
data: _.zipObject(_.map(action.payload, group => group.id),
_.map(action.payload, group => ({
data: group,
isLoading: true,
errorFetching: null,
mode: SNIPPET_GROUP
}))
),
isLoading: false,
errorFetching: null
};
case FETCH_GROUPS_ERROR:
return {
data: null,
isLoading: false,
errorFetching: action.payload.error
};
case FETCH_GROUP_SUCCESS:
return {
data: {...state.data, [action.payload.id]: {
data: action.payload,
isLoading: false,
errorFetching: null,
mode: FULL_GROUP
}},
isLoading: false,
errorFetching: null
};
case FETCH_GROUP_ERROR:
const stateWithoutId = _.omit(state, action.payload.id);
return {
data: {...stateWithoutId},
isLoading: false,
errorFetching: null
};
case CREATE_GROUP_SUCCESS:
debugger;
//TODO: how to let the NewGroup know that a group was created successfuly ?
return { ...state, [action.payload.id]: {
data: action.payload,
isLoading: true,
errorFetching: null,
mode: SNIPPET_GROUP
}};
default:
return state;
}
}
这是操作创建者:
export function groupsFetchSucceeded(response) {
return {
type: FETCH_GROUPS_SUCCESS,
payload: response
}
}
export function groupsFetchErrored(errorWithId) {
return {
type: FETCH_GROUPS_ERROR,
payload: errorWithId
}
}
export function groupCreateSucceeded(group) {
return {
type: CREATE_GROUP_SUCCESS,
payload: group
}
}
export function groupCreateErrored(errorWithId) {
return {
type: CREATE_GROUP_ERROR,
payload: response
}
}
export function groupFetchSucceeded(groupData) {
return {
type: FETCH_GROUP_SUCCESS,
payload: groupData
}
}
export function groupFetchErrored(errorWithId) {
//handle the error here
return {
type: FETCH_GROUP_ERROR,
payload: errorWithId
}
}
这是组件。请忽略这是一个redux表单的事实,我不管它是否是redux表单,我只是在寻找一个大致的想法。您可以假设它是一个包含mapStateToProps和mapDispatchToProps以及其他相关内容的react redux组件
import { createGroup } from '../../actions';
import { validateName, validateDescription } from '../../helpers/group_utils';
import { renderField, validate } from '../../helpers/form_utils';
const validators = {
name: validateName,
description: validateDescription
};
class NewGroup extends Component {
_onSubmit(values) {
this.props.createGroup(values);
}
render() {
const { handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this._onSubmit.bind(this))}>
<Field name="name" label="Name" type="text" fieldType="input" component={renderField.bind(this)}/>
<Field name="description" label="Description" type="text" fieldType="input" component={renderField.bind(this)}/>
<button type="submit" className="btn btn-primary">Create</button>
<button type="button" className="btn btn-primary" onClick={() => this.props.history.push('/group')}>Cancel</button>
</form>
</div>
);
}
}
export default reduxForm({
validate,
//a unique id for this form
form:'NewGroup',
validators
})(
connect(null, { createGroup })(NewGroup)
);
问题的棘手之处在于,虽然您希望在redux状态下记录所有请求状态,但如果处理不当,请求数量可能会成倍增加,占用状态的大量容量。另一方面,我不认为区分请求数据和状态数据有什么大不了的:您只需要在状态中将它们分开:
{
groups: {gid1: group1, gid2: group2, ....},
groupRequests: {grid1: request1, grid2: request2, ...},
expenses: {eid1: expense1, eid2: expense2, ...},
...
}
其中每个组数据包含:
{
data: groupData,
lastRequestId: grid // optional
}
{
groupId: gid,
isLoading: true/false,
errorFetching: message
}
每个组请求数据包含:
{
data: groupData,
lastRequestId: grid // optional
}
{
groupId: gid,
isLoading: true/false,
errorFetching: message
}
当发送新请求时,您可以在groupRequests中更新并跟踪它;NewGroup组件只需要持有groupId就可以找到最近发出的请求并查看其状态。当您需要了解以前请求的状态时,请从列表中获取它们
同样,这种方法的问题是groupRequests中的大多数数据都是一次性使用的,这意味着在某个时刻,例如当NewGroup组件关闭时,您甚至不再需要它。所以,请确保在groupRequest变得太大之前正确地丢弃旧的请求状态
我的建议是,在处理redux状态时,尝试将其正常化。如果您需要1-n关系组数据和创建组的请求数据,请将其进一步分解,而不是将它们分组在一起。并尽可能避免存储一次性使用的数据。如果响应成功,为什么不只发送操作并关闭模式?在本例中,我将在NewGroup组件中执行请求。编辑:这里更广泛的问题是:为什么您需要知道以前所有的请求调用失败/成功?我不需要知道这些请求调用。但我希望避免回调,并坚持将应用程序状态作为我整个应用程序的唯一真实来源。如果不了解更多关于当前数据如何通过应用程序的信息,这是一个非常难以回答的问题。你可以包括关于动作创建者定义的更多信息,以及如何/何时调用它们,b动作类型,即:你有一个动作添加组还是多个动作添加组,开始添加组,完成添加组,c你的减速机看起来像什么,d应用成功或失败后会发生什么?在何处以及如何使用iProcessed?呈现此数据的组件中会发生什么情况?@agm1984我在update1thanks下添加了代码。我认为这是个好建议。我也想知道,如果你想处理这种情况,你会怎么做?您会使用回调吗?redux对此有什么建议吗?我认为这应该是一个非常常见的问题。应该需要从React组件回调到redux存储来处理这些情况。在您的情况下,我认为您应该创建一个操作,在NewGroup组件卸载时调用ComponentWillUnmount来通知存储以删除未使用的记录。如果希望根据时间戳清除请求,redux saga间隔检查也会有所帮助。