javascript - 状态为对象数组与由 id 键控的对象

标签 javascript redux spread-syntax

在关于 Designing the State Shape 的章节中,文档建议将您的状态保存在由 ID 键控的对象中:

Keep every entity in an object stored with an ID as a key, and use IDs to reference it from other entities, or lists.

他们接着说

Think of the app’s state as a database.

我正在处理过滤器列表的状态形状,其中一些将打开(它们显示在弹出窗口中),或已选择选项。当我阅读“将应用程序的状态视为数据库”时,我想到将它们视为 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',
  }
}

理论上,只要 data is serializable (under the heading "State") 就没关系.

所以我愉快地采用了对象数组方法,直到我编写了我的 reducer。

通过 object-keyed-by-id 方法(以及自由使用扩展语法),reducer 的 OPEN_FILTER 部分变为

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) 对象按 ID 键控的方法似乎更难处理 API 的标准 JSON 输入/输出。 (这就是为什么我首先使用对象数组的原因。)所以如果你使用这种方法,你是否只使用一个函数在 JSON 格式和状态形状格式之间来回转换它?这看起来很笨拙。 (尽管如果你提倡这种方法,你的部分推理是否比上面的对象数组缩减器更简单?)

3) 我知道 Dan​​ Abramov 将 redux 设计为理论上与状态数据结构无关(正如 "By convention, the top-level state is an object or some other key-value collection like a Map, but technically it can be any type," 强调我的建议)。但是考虑到上述情况,是否只是“建议”将其保留为由 ID 键入的对象,或者是否存在其他无法预料的痛点我将通过使用使其成为对象的数组来运行,以至于我应该中止它计划并尝试坚持使用 ID 键控的对象?

最佳答案

Q1:reducer 的简单性是因为不必搜索数组来找到正确的条目。不必搜索数组是优点。选择器和其他数据访问器可能并且经常通过 id 访问这些项目。每次访问都必须搜索数组成为性能问题。当您的阵列变大时,性能问题会急剧恶化。此外,随着您的应用程序变得越来越复杂,在更多地方显示和过滤数据,问题也会变得更加严重。这种组合可能是有害的。通过id访问项目,访问时间从O(n)变为O(1),对于大的n (这里是数组项)有很大的不同。

Q2:可以使用normalizr帮助您完成从 API 到商店的转换。从 normalizr V3.1.0 开始,您可以使用 denormalize 走另一条路。也就是说,应用程序通常更多地是消费者而不是数据生产者,因此通常更频繁地转换为存储。

问题 3:使用数组会遇到的问题与其说是存储约定和/或不兼容性问题,不如说是性能问题。

关于javascript - 状态为对象数组与由 id 键控的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38445006/

相关文章:

javascript - 使用 Rails 两次 Angular 加载页眉和页脚

javascript - 如何使用服务器渲染 + 流在 React 中管理标题、元标记等?

javascript - 如何使扩展运算符仅通过非函数属性进行枚举?

php - 使用 while 循环回显 mysql_fetch_row 超过 1 行?

javascript - 将 less/scss/sass 与包含莫里斯图表等颜色的插件一起使用

reactjs - 为什么在handleLogin方法中this.props未定义?

javascript - 通过 React Router 传递在 app.jsx 级别创建的 props

javascript - 如何在 JavaScript 中使用扩展运算符更新内部对象数组

javascript - 用空原型(prototype)替换对象

javascript - 如何动态地将新列添加到 HTML 表