想象一下,您开发了一些react-redux应用程序(具有全局不可移植的树状态)。有些数据在不同的树枝中有一些规则关系,比如表之间的SQL关系。
即。如果你正在研究一些公司的待办事项清单,每个待办事项都与具体用户有关系(多对一)。如果你添加一些新用户,你应该添加空的待办事项列表(到该州的其他分支)。或删除用户意味着您应该将用户的待办事项重新分配给某些(默认管理员)用户。
您可以直接将此关系硬编码为源代码。它很好,工作正常。 但想象一下,你有这么多数据的小关系。一些小的“自动”操作/检查(支持/保护关系)会根据规则自动执行。
可能存在一些常见的方法/库/经验来通过一些规则来实现:像SQL中的触发器:
on add new user => add new empty todos
on user delete => reassign todos to default user
答案 0 :(得分:1)
这里有两个解决方案。我不认为你应该在redux应用程序中使用这种功能,所以我的第一个例子并不是你想要的,但我认为更加圆锥形。第二个例子采用DB / orm模式,它可以正常工作,但不是圆锥形,需要
这些可以通过vanilla redux和redux-thunk
安全地添加。 Redux thunk基本上允许你发送一个单独的动作,它自己发送多个其他动作 - 所以当你触发CREATE_USER
时,只需按触发CREATE_EMPTY_TODO
,CREATE_USER
和ASSIGN_TODO
行动中的createUser
。要删除用户,请REASSIGN_USER_TODOS
然后DELETE_USER
。
对于您提供的示例,以下是示例:
function createTodoList(todos = []) {
return dispatch => {
return API.createTodoList(todos)
.then(res => { // res = { id: 15543, todos: [] }
dispatch({ type: 'CREATE_TODO_LIST_SUCCESS', res });
return res;
});
}
}
function createUser (userObj) {
return dispatch => {
dispatch(createTodoList())
.then(todoListObj => {
API.createUser(Object.assign(userObj, { todoLists: [ todoListObj.id ] }))
.then(res => { // res = { id: 234234, name: userObj.name, todoLists: [ 15534 ]}
dispatch({ type: 'CREATE_USER_SUCCESS', payload: res });
return res;
})
})
.catch(err => console.warn('Could not create user because there was an error creating todo list'));
}
}
删除,没有异步的东西。
function deleteUser (userID) {
return (dispatch, getState) => {
dispatch({
type: 'REASSIGN_USER_TODOS',
payload: {
fromUser: userID,
toUser: getState().application.defaultReassignUser
});
dispatch({
type: 'DELETE_USER',
payload: { userID }
});
}
}
如评论中所述,此方法的问题在于,新开发人员可能会在不知道已存在的操作的情况下进入项目,然后创建自己的createUser
版本,但不会知道创造待办事项。虽然你永远无法完全剥夺他们编写错误代码的能力,但你可以通过让你的行为更有条理来试图更加防守。例如,如果您的操作如下所示:
const createUserAction = {
type: 'CREATE',
domain: 'USERS',
payload: userProperies
}
你可以有一个像这样的
结构的reducerfunction createUserTrigger (state, userProperies) {
return {
...state,
todoLists: {
...state.todoLists,
[userProperies.id]: []
}
}
}
const triggers = {
[CREATE]: {
[USERS]: createUserTrigger
}
}
function rootReducer (state = initialState, action) {
const { type, domain, payload } = action;
let result = state;
switch (type) {
case CREATE:
result = {
...state,
[domain]: {
...state[domain],
[payload.id]: payload
}
};
break;
case DELETE:
delete state[domain][payload.id];
result = { ...state };
break;
case UPDATE:
result = {
...state,
[domain]: {
...state[domain],
[payload.id]: _.merge(state[domain][payload.id], payload)
}
}
break;
default:
console.warn('invalid action type');
return state;
}
return triggers[type][domain] ? triggers[type][domain](result, payload) : result;
}
在这种情况下,您基本上强迫所有开发人员使用非常有限的一组操作类型。它非常严格,我不是真的推荐它,但我认为它符合您的要求。