这是一个设计问题,但我想知道是否有最好的做法来处理这种情况。
我有一个react redux应用程序。 app状态结构如下所示:
{
groups: {gid1: group1, gid2: group2, ....},
expenses: {eid1: expense1, eid2: expense2, ...},
//.... the rest
}
NewGroup
组件旨在创建一个新组。如果创建请求(对后端的ajax请求)成功,则会将其添加到应用程序状态的组列表中。作为模态的NewGroup
已关闭,组列表将更新。
如果请求未成功,则不应关闭NewGroup
组件。
主要问题是:我是否应该在应用程序状态中合并请求状态(如果成功或不成功,后一种情况下的错误消息,如果结果是否返回等)?这是我真正怀疑的地方,因为它使应用程序状态非常丑陋,大而且在某些情况下它无法处理某些情况,在这种情况下:创建一个新组。
假设我将响应状态代码和错误消息添加到应用程序状态:
{
groups: {
newGroupId1: {
data: newGroupData1,// null in case it was not successful
isLoading: true/false, // if the call is returned or not
errorFetching: message1
}
}
}
在对后端的第二个不成功的创建请求中,无法区分先前和当前的呼叫,因为它们都具有errorFetching
和类似的isLoading
值。 (例如,errorFetching
和isLoading
都有“找不到群组”和“{1}}
在使用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形式,我不在乎它是一种还原形式,我正在寻找一个大概的想法。您可以假设它是react-redux
组件mapStateToProps
和mapDispatchToProps
以及其他相关内容。
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)
);
答案 0 :(得分:1)
你问题的棘手部分是,虽然你想在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
}
发送新请求时,您会在groupRequests
中更新并在那里进行跟踪; NewGroup
组件只需要持有groupId来查找最近发出的请求并查看其状态。当您需要知道先前请求的状态时,请从列表中获取它们。
同样,这种方法的问题在于groupRequests
中的大部分数据都是一次性使用的,这意味着在某些时候(例如当NewGroup
组件关闭时),你就不会这样做。甚至还需要它。因此,请确保在groupRequest
变得过大之前正确地抛弃旧的请求状态。
我的建议是,在处理redux状态时,请尝试将其正常化。如果您需要1-n关系(组数据和创建组的请求数据),请将其进一步分解,而不是将它们组合在一起。并避免尽可能多地存储一次性使用的数据。