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

标签 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 状态下的父项目。

处理这个问题的最佳方法是什么?两个 reducer 都需要采取措施来处理这个问题吗?或者是否有某种方式 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 都被限定在一个根键的范围内。 实体会被持久化,但条件不会。状态的所有其他部分均使用reselect 进行计算。我很想知道其他人如何在仅前端的应用程序中解决类似的问题。

最佳答案

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

这样当你调度CREATE_TODO时,你只需要todos reducer 来监听。

保持 reducer 解耦

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

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

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

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

    mapStateToProps 中调用 state.todos.filter(todo => todo.project == currentProject.id) 是比弄清楚下一个 id 应该是什么更好的解决方案位于 View 中并通过操作传递它。

    如果这是通过数据库完成的,那么您可以将类似的内容与 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 的后端,那么您可以执行上述操作,让两个 reducer 监听事件并同时将待办事项分配给项目,并将项目分配给待办事项。但我仍然不建议这样做。

  3. 由于缺乏单一事实来源,您可能会面临数据不同步的风险。如果您的项目 reducer 说一个项目拥有一个 id === 3 的待办事项,但该待办事项却说另一个项目拥有它,那么该待办事项属于谁?显然已经发生了一个错误,但是只要让一个 child 跟踪 parent 就可以完全避免这种情况。

    不过,如果您使用数据库,那么数据库应该使这些内容保持同步(错误的表面积仍然更大,但可能性较小)。在这种情况下,只要您的客户端数据始终反射(reflect)服务器数据,就应该没问题。

关于reactjs - redux中如何处理父子数据关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33312198/

相关文章:

javascript - ReactJS + Redux : How to directly navigate to a page (skip login) if token is in local storage?

javascript - 数组中的 Redux 项目的 id 正在更新

javascript - 表单正在清除空白输入上一组数据

javascript - 分割很长的 JavaScript 字符串

javascript - 出现错误 : Module parse failed: . .. 意外字符 '#'

javascript - 使用 React-Redux 时 App 类出错 "connect "

javascript - 使用reactjs在tic tac toe应用程序中渲染图像

javascript - 如何从 npm 声明 javascript 子模块的类型?

javascript - 在 HOC 中包装数据获取组件以在加载时显示微调器

javascript - Uncaught ReferenceError : React is not defined