在Designing the State Shape章节中,文档建议将您的状态保存在由 ID 键入的对象中:
将对象中的每个实体保存为以 ID 作为键存储,并使用 ID 从其他实体或列表中引用它。
他们继续陈述
将应用程序的状态视为数据库。
我正在处理过滤器列表的状态形状,其中一些将打开(它们显示在弹出窗口中),或者已选择选项。当我阅读“将应用程序的状态视为数据库”时,我想到将它们视为 JSON 响应,因为它将从 API(本身由数据库支持)返回。
所以我认为它是
[{
id: '1',
name: 'View',
open: false,
options: ['10', '11', '12', '13'],
selectedOption: ['10'],
parent: null,
},
{
id: '10',
name: 'Time & Fees',
open: false,
options: ['20', '21', '22', '23', '24'],
selectedOption: null,
parent: '1',
}]
但是,文档建议的格式更像
{
1: {
name: 'View',
open: false,
options: ['10', '11', '12', '13'],
selectedOption: ['10'],
parent: null,
},
10: {
name: 'Time & Fees',
open: false,
options: ['20', '21', '22', '23', '24'],
selectedOption: null,
parent: '1',
}
}
从理论上讲,只要数据是可序列化的(在“状态”标题下) ,这无关紧要。
所以我很高兴地使用了对象数组方法,直到我开始编写我的 reducer。
使用 object-keyed-by-id 方法(以及自由使用扩展语法),OPEN_FILTER
reducer 的部分变为
switch (action.type) {
case OPEN_FILTER: {
return { ...state, { ...state[action.id], open: true } }
}
而使用对象数组方法,它更冗长(并且依赖于辅助函数)
switch (action.type) {
case OPEN_FILTER: {
// relies on getFilterById helper function
const filter = getFilterById(state, action.id);
const index = state.indexOf(filter);
return state
.slice(0, index)
.concat([{ ...filter, open: true }])
.concat(state.slice(index + 1));
}
...
所以我的问题有三个:
1)reducer 的简单性是采用 object-keyed-by-id 方法的动机吗?这种状态形状还有其他优点吗?
和
2) 似乎 object-keyed-by-id 方法使得处理 API 的标准 JSON 输入/输出变得更加困难。(这就是我首先使用对象数组的原因。)因此,如果您采用这种方法,您是否只是使用一个函数在 JSON 格式和状态形状格式之间来回转换它?这似乎很笨拙。(尽管如果您提倡这种方法,那么您的部分推理是否比上面的对象数组缩减器更笨重?)
和
3)我知道 Dan Abramov 设计的 redux 在理论上是与状态数据结构无关的(正如“按照惯例,顶级状态是一个对象或其他一些键值集合,如 Map,但从技术上讲,它可以是任何类型,”强调我的)。但是鉴于上述情况,是否只是“建议”将其保留为由 ID 键入的对象,或者我是否会遇到其他无法预料的痛点,方法是使用一组对象,使我应该中止它计划并尝试坚持使用 ID 键入的对象?