我有一个类型如下的数据结构:
export interface IGroup {
id: number;
name: string;
groupTypeId: number;
items: IItem[];
groups: IGroup[];
}它递归地表示"Group“和"Group”以及"Group“和"Item”之间的多对多关系。组由项目和子组组成。项目只派生为简单类型和其他元数据,但不能有子项。单个组表示层次结构的顶层。
我目前有一些组件、钩子等可以递归地获取单个组并创建一个编辑/创建表单,如下所示:

我让这个表单“处理”测试数据,在保存时生成标准数据输出,如下所示:
{
"1-1": {
"name": "ParentGroup",
"groupType": 2
},
"2-4": {
"name": "ChildGroup1",
"groupType": 1
},
"2-9": {
"name": "ChildGroup2",
"groupType": 3
},
"2-1": {
"itemType": "FreeForm",
"selectedName": "Testing",
"selectedClass": 5
},
"2-2": {
"itemType": "FreeForm",
"selectedName": "DisplayTest",
"selectedClass": 5
},
"3-4": {
"itemType": "EnumValue",
"selectedItem": {
"id": 12900503,
"name": "TRUE"
}
},
"3-5": {
"itemType": "EnumValue",
"selectedItem": {
"id": 12900502,
"name": "FALSE"
}
},
"3-9": {
"itemType": "FreeForm",
"selectedName": "Test",
"selectedClass": 5
},
"3-10": {
"itemType": "FreeForm",
"selectedName": "Tester",
"selectedClass": 5
},
"3-11": {
"itemType": "FreeForm",
"selectedName": "TestTest",
"selectedClass": 5
}
}由于没有其他保证的唯一标识符(如果用户正在编辑,则期望组在db中具有in,但是如果用户在表单中添加新组则不是),所以这些对象的“关键”是网格列和行。否则,名称是可以更改的输入表单。)这是有意义的,并且很容易以这种方式对键进行建模。如果将另一个组或项目添加到层次结构中,则可以将其与其列和行一起添加。
我遇到的问题是,我希望能够有一个add按钮,它可以添加到组、项目或组数组中,这样就可以在层次结构中创建新的行。我的表单应该可以处理这些新条目。例如。
"1-1": {
groups: [..., {}],
items: [..., {}]
}但我拥有的唯一数据结构是嵌套得很深的IGroup。这不利于使用as状态,也不适合添加到这种深度嵌套的状态中。
我的另一个问题是,我需要能够将项和组映射到它们的位置,以便我可以将多对多表转换到相应的数据库,并插入新的组/项。
建议的解决方案:我在想,我可以创建规范化的对象来存储状态,而不是将一个组放入我的递归组件中。我会有一个对象键控的列-行,它将容纳所有的组。另一个以列-行为关键字来保存所有项。然后我想我需要另外两个对象来保存多对多的关系,比如Group to Group和Group to Item。
在我从表单中获得数据后,我希望可以遍历这些状态对象,以这种方式找到层次结构,并将必要的数据发送到数据库。
我看到这是很多数据结构来保存这些数据,我不确定这是否是实现这一目标的最佳方式,因为我的建模结构。我也刚刚开始使用Redux Toolkit,所以我对Redux Toolkit比较熟悉,但还不足以让我明白如何在这里应用它们来帮助我。我真的一直在努力弄清楚这一点,任何帮助或指导,使这一点更容易,将非常感谢。
发布于 2020-04-10 16:17:43
请使用规范化。每个实体都有一个单一的真值来源,这使得读写状态变得容易得多。
要做到这一点,请尝试normalized-reducer。这是一个学习曲线较低的简单高阶降阶算法。
这是一个正在工作的CodeSandbox example of it,它实现了一个组/项复合树,与您的问题非常相似。
基本上,您将定义树的架构:
const schema = {
group: {
parentGroupId: { type: 'group', cardinality: 'one', reciprocal: 'childGroupIds' },
childGroupIds: { type: 'group', cardinality: 'many', reciprocal: 'parentGroupId' },
itemIds: { type: 'item', cardinality: 'many', reciprocal: 'groupId' }
},
item: {
groupId: { type: 'group', cardinality: 'one', reciprocal: 'itemIds' }
}
};然后将其传递到库的顶级函数中:
import normalizedSlice from 'normalized-reducer';
export const {
emptyState,
actionCreators,
reducer,
selectors,
actionTypes,
} = normalizedSlice(schema);然后将reducer连接到您的应用程序中(与React useReducer和Redux store reducers一起使用),并使用selectors和actionCreators来读写状态。
https://stackoverflow.com/questions/61083273
复制相似问题