[英]React Redux - Reducer with CRUD - best practices?
我为User
实体编写了简单的reducer,现在我想在切换操作类型和返回状态时为其应用最佳实践。 仅提及一下,我将动作类型提取到了单独的文件actionsTypes.js
。
actionsTypes.js
内容:
export const GET_USERS_SUCCESS = 'GET_USERS_SUCCESS';
export const GET_USER_SUCCESS = 'GET_USER_SUCCESS';
export const ADD_USER_SUCCESS = 'ADD_USER_SUCCESS';
export const EDIT_USER_SUCCESS = 'EDIT_USER_SUCCESS';
export const DELETE_USER_SUCCESS = 'DELETE_USER_SUCCESS';
第一个问题,是否有针对FAILED
案例的操作类型是强制性的? 例如,要添加GET_USERS_FAILED
等并在usersReducer中处理它们?
根减少剂是:
const rootReducer = combineReducers({
users
});
有usersReducer的代码,我在代码中放入了注释/问题,并寻求答案(处理操作类型的最佳实践是什么):
export default function usersReducer(state = initialState.users, action) {
switch (action.type) {
case actionsTypes.GET_USERS_SUCCESS:
// state of usersReducer is 'users' array, so I just return action.payload where it is array of users. Will it automatically update users array on initial state?
return action.payload;
case actionsTypes.GET_USER_SUCCESS:
// What to return here? Just action.payload where it is just single user object?
return ;
case actionsTypes.ADD_USER_SUCCESS:
// what does this mean? Can someone explain this code? It returns new array, but what about spread operator, and object.assign?
return [...state.filter(user => user.id !== action.payload.id),
Object.assign({}, action.payload)];
case actionsTypes.EDIT_USER_SUCCESS:
// is this ok?
const indexOfUser = state.findIndex(user => user.id === action.payload.id);
let newState = [...state];
newState[indexOfUser] = action.payload;
return newState;
case actionsTypes.DELETE_USER_SUCCESS:
// I'm not sure about this delete part, is this ok or there is best practice to return state without deleted user?
return [...state.filter(user => user.id !== action.user.id)];
default:
return state;
}
}
我不是一位经验丰富的开发人员,但请允许我回答您到目前为止所学到的问题。
第一个问题,是否有针对失败案例的操作类型是强制性的? 例如,要添加GET_USERS_FAILED等并在usersReducer中处理它们?
这不是强制性的,但是如果您打算向客户提供反馈,那就太好了。 例如,您启动了GET_USERS
进程,但由于某种原因它失败了。 客户端没有任何反应,没有更新等。因此,您的客户端不知道它失败了,并且想知道为什么什么也没发生。 但是,如果遇到故障案例并捕获到错误,则可以通知您的客户有错误。
为此,您可以使用两个示例来使用GET_USERS_FAILED
操作类型。 您的userReducers
一个,而说一个error
或feedback
减少器则是一个。 第一个返回状态,因为您的过程失败了,您无法获得所需的数据,因此无论如何都不想改变状态。 第二个更新您的反馈减少器并可以更改状态,可以说是error
然后在组件中捕获该状态,如果error
状态为true,则会向客户端显示一条好消息。
usersReducer的状态是“用户”数组,所以我只返回action.payload,它是用户数组。 它将在初始状态下自动更新用户数组吗?
case actionsTypes.GET_USERS_SUCCESS:
return action.payload;
如果您通过单个请求获取整个用户,则可以。 这意味着作为数组的action.payload成为您的状态。 但是,如果您不希望通过单个请求获取所有用户(例如分页),那还不够。 您需要与获取的状态保持一致。
case actionsTypes.GET_USERS_SUCCESS:
return [...state, ...action.payload];
在这里,我们使用传播语法 。
显然,它可以扩展所提供的内容:)您可以以多种方式将其用于数组以及对象。 您可以检查文档。 但是这里有一些简单的例子。
const arr = [ 1, 2, 3 ];
const newArr = [ ...arr, 4 ];
// newArr is now [ 1, 2, 3, 4 ]
我们将arr
散布到一个新数组中,并添加4。
const obj = { id: 1, name: "foo, age: 25 };
const newObj = { ...obj, age: 30 };
// newObj is now { id: 1, name: "foo", age: 30 }
在这里,我们将obj
散布到新对象中并更改了age属性。 在两个示例中,我们都不会对原始数据进行突变。
这里要返回什么? 只是action.payload在哪里,它只是单个用户对象?
case actionsTypes.GET_USER_SUCCESS:
return ;
可能您不能直接在此reducer中使用此操作。 因为这里的状态将您的用户保留为数组。 您想对拥有某种方式的用户做什么? 假设您要保留“选定”用户。 您可以为此创建一个单独的reducer或在此处更改您的状态,使其成为对象并持有selectedUser
属性并用此属性对其进行更新。 但是,如果您更改状态的形状,则所有其他异径管零件都需要更改,因为您的状态将是这样的:
{
users: [],
selectedUser,
}
现在,您的状态不再是数组,而是一个对象。 您的所有代码都必须根据该代码进行更改。
这是什么意思? 有人可以解释此代码吗? 它返回新数组,但是散布运算符和object.assign呢?
case actionsTypes.ADD_USER_SUCCESS:
return [...state.filter(user => user.id !== action.payload.id), Object.assign({}, action.payload)];
我已经尝试解释传播语法。 Object.assign将一些值复制到目标或对其进行更新或合并其中两个。 该代码的作用是什么?
首先,它获取您的状态,对其进行过滤,并返回与您的action.payload不相等的用户,即正在添加的用户。 这将返回一个数组,因此将其展开并将其与Object.assign部分合并。 在Object.assign部分中,它需要一个空对象并将其与用户合并。 所有这些值将创建一个新数组,这是您的新状态。 假设您的状态如下:
[
{ id: 1, name: "foo" },
{ id: 2, name: "bar" },
]
您的新用户是:
{
id: 3, name: "baz"
}
这是这段代码的作用。 首先,它过滤所有用户,并且由于过滤条件不匹配,它返回所有用户(状态),然后将其散布(别忘了,过滤器返回一个数组,然后我们将该数组散布到另一个数组中):
[ { id: 1, name: "foo"}, { id: 2, name: "bar" } ]
现在,Object.assign部分完成其工作,并将空对象与用户对象action.payload合并。 现在我们的最终数组将如下所示:
[ { id: 1, name: "foo"}, { id: 2, name: "bar" }, { id: 3, name: "baz" } ]
但是,实际上,这里不需要Object.assign。 为什么我们还要麻烦地将对象与空对象合并? 因此,此代码执行相同的工作:
case actionsTypes.ADD_USER_SUCCESS:
return [...state.filter(user => user.id !== action.payload.id), action.payload ];
这个可以吗?
case actionsTypes.EDIT_USER_SUCCESS:
const indexOfUser = state.findIndex(user => user.id === action.payload.id);
let newState = [...state];
newState[indexOfUser] = action.payload;
return newState;
对我来说似乎还可以。 您无需直接更改状态,使用扩展语法来创建新的状态,更新相关部分,并最终使用此新状态来设置状态。
我不确定这个删除部分,可以吗?还是有一种最佳做法是在不删除用户的情况下返回状态?
case actionsTypes.DELETE_USER_SUCCESS:
return [...state.filter(user => user.id !== action.user.id)];
再次,对我来说似乎还可以。 您可以过滤已删除的用户并根据该状态更新您的状态。 当然,还有其他情况需要考虑。 例如,您是否有后端流程? 您是否向数据库添加或删除用户? 如果所有部分都为是,则需要确保后端过程成功,然后需要更新状态。 但这是一个不同的话题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.