Redux.js和关系数据

时间:2016-02-01 10:46:33

标签: javascript relational-database redux immutable.js

想象一下,您开发了一些react-redux应用程序(具有全局不可移植的树状态)。有些数据在不同的树枝中有一些规则关系,比如表之间的SQL关系。

即。如果你正在研究一些公司的待办事项清单,每个待办事项都与具体用户有关系(多对一)。如果你添加一些新用户,你应该添加空的待办事项列表(到该州的其他分支)。或删除用户意味着您应该将用户的待办事项重新分配给某些(默认管理员)用户。

您可以直接将此关系硬编码为源代码。它很好,工作正常。 但想象一下,你有这么多数据的小关系。一些小的“自动”操作/检查(支持/保护关系)会根据规则自动执行。

可能存在一些常见的方法/库/经验来通过一些规则来实现:像SQL中的触发器:

on add new user => add new empty todos

on user delete => reassign todos to default user

1 个答案:

答案 0 :(得分:1)

这里有两个解决方案。我不认为你应该在redux应用程序中使用这种功能,所以我的第一个例子并不是你想要的,但我认为更加圆锥形。第二个例子采用DB / orm模式,它可以正常工作,但不是圆锥形,需要

这些可以通过vanilla redux和redux-thunk安全地添加。 Redux thunk基本上允许你发送一个单独的动作,它自己发送多个其他动作 - 所以当你触发CREATE_USER时,只需按触发CREATE_EMPTY_TODOCREATE_USERASSIGN_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
}

你可以有一个像这样的

结构的reducer
function 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;
}

在这种情况下,您基本上强迫所有开发人员使用非常有限的一组操作类型。它非常严格,我不是真的推荐它,但我认为它符合您的要求。