如何在 redux 中处理父子数据关系
How to handle parent child data relationships in 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
计算的。我很想知道其他人是如何在纯前端应用程序中解决类似问题的。
当项目引用它们的待办事项时,反之亦然,您就是在复制数据。除非你正在处理一个非常大的集合,否则我建议不要使用这种模式。相反,每当您需要与项目匹配的待办事项列表时,过滤待办事项集合。像 reselect
这样的东西是理想的选择。
这样当你调度 CREATE_TODO
时,你只需要 todos
reducer 来监听。
让你的减速器解耦。
reducer 中的调度操作是 anti-pattern。您不能在一个 reducer 中做某事并将该信息直接传递给另一个。更好的解决方案是
dispatch({ type: CREATE_TODO, payload: { text: 'dsfdf' })
dispatch({ type: ASSOCIATE_TODO_WITH_PROJECT, payload: { todo: todoid, project: 2 })
但即使这样也行不通,因为您不知道 todoid
是什么。这让我想到...
您不必在创建待办事项之前就知道它的 ID。在你的 reducer 设置中,你需要知道 todo 的 id 才能将它添加到项目中。这意味着您需要在操作负载中提供它。但是你的视图将不得不生成下一个 id,这并不理想。
在 mapStateToProps
中调用 state.todos.filter(todo => todo.project == currentProject.id)
比找出下一个 ID 应该在视图中并通过操作传递它更好的解决方案。
如果这是用数据库完成的,那么你会用这样的东西 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 监听事件并同时将待办事项分配给项目和项目给待办事项。但我仍然不建议这样做。
您冒着数据不同步的风险,因为您缺乏单一的真实来源。如果你的项目 reducer 说一个项目拥有 id === 3
的待办事项,但那个待办事项说另一个项目拥有它,那么那个待办事项属于谁?显然出现了一个错误,但是可以通过只让一个 child 跟踪 parent.
来完全避免这个错误
尽管如此,如果您正在使用数据库,那么数据库应该使这些内容保持同步(错误的表面积仍然更大,但可能性较小)。在这种情况下,只要您的客户端数据始终反映服务器数据,您应该没问题。
我正在构建一个简单的待办事项应用程序,用户可以在其中创建项目然后添加待办事项。我相信我的状态应该是这样的:
{
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
计算的。我很想知道其他人是如何在纯前端应用程序中解决类似问题的。
当项目引用它们的待办事项时,反之亦然,您就是在复制数据。除非你正在处理一个非常大的集合,否则我建议不要使用这种模式。相反,每当您需要与项目匹配的待办事项列表时,过滤待办事项集合。像 reselect
这样的东西是理想的选择。
这样当你调度 CREATE_TODO
时,你只需要 todos
reducer 来监听。
让你的减速器解耦。
reducer 中的调度操作是 anti-pattern。您不能在一个 reducer 中做某事并将该信息直接传递给另一个。更好的解决方案是
dispatch({ type: CREATE_TODO, payload: { text: 'dsfdf' }) dispatch({ type: ASSOCIATE_TODO_WITH_PROJECT, payload: { todo: todoid, project: 2 })
但即使这样也行不通,因为您不知道
todoid
是什么。这让我想到...您不必在创建待办事项之前就知道它的 ID。在你的 reducer 设置中,你需要知道 todo 的 id 才能将它添加到项目中。这意味着您需要在操作负载中提供它。但是你的视图将不得不生成下一个 id,这并不理想。
在
mapStateToProps
中调用state.todos.filter(todo => todo.project == currentProject.id)
比找出下一个 ID 应该在视图中并通过操作传递它更好的解决方案。如果这是用数据库完成的,那么你会用这样的东西
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 监听事件并同时将待办事项分配给项目和项目给待办事项。但我仍然不建议这样做。
您冒着数据不同步的风险,因为您缺乏单一的真实来源。如果你的项目 reducer 说一个项目拥有
来完全避免这个错误id === 3
的待办事项,但那个待办事项说另一个项目拥有它,那么那个待办事项属于谁?显然出现了一个错误,但是可以通过只让一个 child 跟踪 parent.尽管如此,如果您正在使用数据库,那么数据库应该使这些内容保持同步(错误的表面积仍然更大,但可能性较小)。在这种情况下,只要您的客户端数据始终反映服务器数据,您应该没问题。