如何在redux中处理父子数据关系

时间:2015-10-23 22:16:40

标签: reactjs redux

我正在构建一个简单的待办事项应用,用户可以在其中创建项目,然后添加待办事项。我相信我的州应该是这样的:

{
  projects: {
    1: {
      id: 1,
      title: "New Project",
      todos: [1, 2]
    }
  },
  todos: {
    1: {
      id: 1,
      text: "This is the first todo",
      isComplete: true,
      project: 1
    },
    2: {
      id: 2,
      text: "This is the second todo",
      isComplete: false,
      project: 1
    }
  }
}

创建新待办事项时,我需要使用新待办事项更新todos状态,我需要更新projects状态的父项目。

处理此问题的最佳方法是什么?两个减速器都需要采取措施来解决这个问题吗?或者,todos reducer可以调用projects reducer中的更新操作吗?

编辑:以下是我如何通过redux更改数据结构以更好地工作

{
  projects: {
    condition: {
      currentProject: 1
    },
    entities: {
      1: {
        id: 1,
        title: "New Project"
      }
    }
  },
  todos: {
    condition: {
      currentFilter: 'SHOW_ALL'
    },
    entities: {
      1: {
        id: 1,
        text: "This is the first todo",
        isComplete: true,
        project: 1
      },
      2: {
        id: 2,
        text: "This is the second todo",
        isComplete: false,
        project: 1
      }
    }
  }
}

这样,我在根级别组合的每个Reducer都被限定为一个根密钥。 entities是持久的,condition不是。状态的所有其他部分都使用reselect计算。我很想知道其他人是如何在前端应用程序中解决类似问题的。

1 个答案:

答案 0 :(得分:5)

当项目引用其待办事项时,反之亦然,您将重复数据。除非您正在处理一个非常大的集合,否则我建议不要使用该模式。相反,只要您需要与项目匹配的待办事项列表,请过滤todos集合。像reselect这样的东西是理想的。

这样,当您发送CREATE_TODO时,您只需要todos缩减器来收听。

让您的Reducer脱钩

  1. reducers中的调度操作是一种反模式。您无法在一个reducer中执行某些操作,并将该信息直接传递给另一个。更好的解决方案是

    dispatch({ type: CREATE_TODO, payload: { text: 'dsfdf' })
    dispatch({ type: ASSOCIATE_TODO_WITH_PROJECT, payload: { todo: todoid, project: 2 })
    

    但即使这样做也不会有效,因为你不知道todoid是什么。这让我想起......

  2. 在创建待办事项之前,您不必知道待办事项的ID。在您的reducer设置中,您需要知道待办事项的ID才能将其添加到项目中。这意味着您需要在动作有效负载中提供它。但是,你的观点必须生成下一个id,这是不理想的。

    state.todos.filter(todo => todo.project == currentProject.id)中调用mapStateToProps比解决视图中下一个ID应该是什么以及通过操作传递它更好。

    如果使用db完成此操作,那么您将使用redux-thunk

    这样的内容
    export function createTodo(text, project) {
      return function(dispatch) {
        dispatch({ type: CREATE_TODO_PENDING });
        fetch('/todos', { method: 'POST', body: { text: text, project: project } })
          .then(function(response) { // { id: 134452, text: text, project: project }
            dispatch({ type: CREATE_TODO_SUCCESS, payload: response })
          }.catch(err) { dispatch({ type: CREATE_TODO_FAIL }) }
      }
    }
    

    如果您正在使用处理id的后端,那么您可以执行上述操作并让两个reducers侦听事件并同时将todos分配给项目和项目。但我仍然不建议这样做。

  3. 由于缺乏单一的事实来源,您可能会因数据不同步而面临风险。如果你的项目减速器说一个项目拥有一个id === 3的todo,但是todo说一个不同的项目拥有它,那个todo属于哪个?显然已经发生了一个错误,但只有让一个孩子跟踪父母,就可以完全避免这个错误。

    尽管如此,如果您正在使用数据库,那么数据库应该保持这些事情同步(更多的表面区域用于错误,但不太可能)。在这种情况下,只要您的客户数据始终反映服务器数据,您应该没问题。