使用索引可以从多个维度表现数据。

最近我在RC聊天系统浏览关于 JavaScript 的一些讨论时,注意到了Kate Ray的一个问题:

  应该怎样在 redux 存储中结构化我的数据?

的确,这是使用redux时最常见的问题之一。

有很多需要考虑的东西,你经常会像访问一个行列表一样遍历数据吗? 你需要以O(1)的时间复杂度快速访问某些条目吗?

我在实践中得到了一些经验,通常在访问时间和迭代的难易程度之间做一些权衡。

一些常见的方法

如果你需要存储一些每个项目都带有id的数据,可以使用Array, Object, 或者 对象数组来保存。

数组对象[{values}]:
这是最常见的一种范式。它使迭代变得容易,但是不经过迭代和过滤就不能快速访问特定条目。

categories: [  {name: 'abs',  id: '32o8wafe', exercises: ['crunches', 'plank']},  {name: 'arms', id: 'oaiwefjo', exercises: [...]},  {name: 'legs', id: 'aoijwfeo', exercises: [...]},]

以id为索引的对象{id: {values}}:
这种方法可以是你以O(1)的时间复杂度快速访问每个项目,但是在使用object.values()进行迭代时,不能很容易地访问给定项目对应的id。

对象数组 [{id: {values}}]:
这让你可以遍历列表并轻松访问id和值,但是它做到以O(1)的时间复杂度快速访问,因为它是一个数组。

categories: [  {32o8wafe: {name: 'abs',  exercises: [...]},  {oaiwefjo: {name: 'arms', exercises: [...]},  {3oij2e3c: {name: 'legs', exercises: [...]},]

把它像数据库一样构造成由id对行进行索引的结构
在学习redux的过程中,我在Monadical偶然发现了一种不同的方法,它使我们受益于简单的Object.values(state.categories),并能够以O(1)的时间复杂度快速对单个项目的访问:

categories: {  32o8wafe: {id: '32o8wafe', name: 'abs',  exercises: [...]},  oaiwefjo: {id: 'oaiwefjo', name: 'arms', exercises: [...] },  3oij2e3c: {id: '3oij2e3c', name: 'legs', exercises: [...] },}

请注意id既是行的键,同时也是行本身的属性。这一点点重复使我们在访问时间上有了很大的灵活性。这也与Redux文档推荐的归一化(也称扁平)模型兼容。

现在你可以遍历数据了,也可以在迭代时访问id!

Object.values(categories).map(cat => ({id: cat.id, name: cat.name}))

或者通过id快度访问任何项目!

categories[category_id].name

我们将这样组织好的数据发送到前端,前端就不需要做任何处理来生成id: values映射,从而也就减少了错误的产生。在后端很容易做到这一点,因为你很可能从数据库中提取数据,而数据库中已经存在id字段,可以直接将其作为键使用。

索引的力量
请注意,我们上面介绍的结构只是一些行的索引,索引是id。你也可以这样设计自己的存储结构:使用你想要用的字段生成索引,来达到O(1)的时间复杂度进行快速访问

按名称索引类别:

categories_by_name = {  abs: '32o8wafe',  arms: 'oaiwefjo',  legs: '3oij2e3c',}const get_category_by_name = (store, name) =>    store.getState().categories[categories_by_name[name]]

也可以为同样的数据构建尽可能多的索引,这样将使你在任何列上基于O(1)的速度进行访问,就像在数据库中一样。


把你存储的数据想象成为图书馆,可以用索引快速找到任何项目

Normalizr与Reselect

这里描述的模式正是Normalizr库所使用的模式。如果你想把你的数据扁平化(按类型分开),就像我前面介绍的索引概念一样,请阅读Normalizr的文档《Redux Without Profanity docs》。

Redux 和 Normalizr 与 Reselect 配合的也很好,如果你关心性能,并且喜欢有一个中央列表的记忆选择器,可以关注一下。

扩展阅读

  • http://redux.js.org/docs/basics/Reducers.html#designing-the-state-shape

  • http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html

  • https://egghead.io/lessons/javascript-redux-normalizing-the-state-shape

  • https://stackoverflow.com/questions/33940015/how-to-choose-the-redux-state-shape-for-an-app-with-list-detail-views-and-pagina

  • https://stackoverflow.com/questions/34995822/how-to-get-best-practice-react-redux-nested-array-data

  • https://codeburst.io/how-to-store-your-state-data-f17ceca37aa

  • https://tonyhb.gitbooks.io/redux-without-profanity/content/normalizer.html
©著作权归作者所有:来自51CTO博客作者mb5ff980b461ced的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 数据对比分析法,看这篇就够了!
  2. 超级菜鸟怎么学习数据分析
  3. JavaScript数据结构(4):树
  4. 用Excel做数据地图
  5. Excel数据处理(缺失值/重复值/异常值/拆分)
  6. JavaScript 数据结构(2-2):栈与队列-队列篇
  7. 只会环比下降3%的数据分析师还有救吗?
  8. JavaScript 数据结构(2-1):栈与队列-栈篇
  9. 客户端用不着的数据结构之并查集

随机推荐

  1. C#中关于async与await的使用详解
  2. C#中关于表达式树的简单介绍
  3. Rest在asp.net MVC下使用的方法介绍
  4. C#异步之APM模式异步程序开发的示例分享
  5. C#中关于Minutes与TotalMinutes的区别
  6. ASP.NET MVC如何使用Bootstrap的实例分析
  7. C#中关于Cookies的读取实例详解
  8. ASP.NET MVC如何正确运用异步编程技术
  9. C#中关于静态与非静态方法的区别介绍
  10. C#如何使用键值对取代Switch...Case语句