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

sli*_*ler 4 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
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:这是我如何通过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
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Nat*_*gen 5

当项目引用它们的待办事项时,反之亦然,那就是复制数据.除非你正在处理一个非常大的集合,否则我建议不要使用这种模式.相反,只要您需要与项目匹配的待办事项列表,请过滤todos集合.这样的事情reselect是理想的.

这种方式在你发送时CREATE_TODO,你只需要todos减速器来监听.

保持你的减速器分离.

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

    dispatch({ type: CREATE_TODO, payload: { text: 'dsfdf' })
    dispatch({ type: ASSOCIATE_TODO_WITH_PROJECT, payload: { todo: todoid, project: 2 })
    
    Run Code Online (Sandbox Code Playgroud)

    但即使这样也行不通,因为你不知道是什么todoid.这让我想到......

  2. 在创建todo之前,您不必知道todo的id.在reducer设置中,您需要知道todo的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 }) }
      }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

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

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