在 redux 存储中处理来自 API 的排序和过滤集合

Handling sorted and filtered collections coming from APIs in a redux store

Redux guidelines 建议

think at an app's state as a database

在存储资源方面,

更喜欢基于键的对象而不是数组。这完全有道理,因为它简化了处理集合时 99% 的最常见用例:搜索、查找、添加更多、删除、读取...

不幸的是,当涉及到保持可过滤和可排序的资源集合与 API 响应同步时,缺点就会显现出来。例如一个典型的请求:

GET /users?status=active&orderBy=name&orderDir=asc&lastID=1234&limit=10

将 return 过滤、排序和分页的用户列表(数组)。通常情况下,reducer 会使用这个数组做一些类似的事情:

users: {...state.users, keyBy(action.payload, 'id')}

这会将新数据与之前获取的数据合并打破从 APIS 完成的计算。 然后,应用程序必须对集合执行第二次客户端计算以重建预期列表。这导致:

另一个缺点是,如果您要实现某种无限加载,则您必须跟踪 lastID,因为在合并结果后无法推断出最后加载的 ID 是什么。

所以问题:

设计必须处理通过 API 获取的 sorted/filterd/paged 数据的存储和缩减程序的最佳方法是什么?

一种常见的方法是将对象索引映射和排序的对象列表保存在不同的结构中。

示例减速器(使用ramda):

function reducer(state, action) {
  if (action.type == 'USERS_LOADED') {
    return r.merge(state, {
      userIndex: ramda.reduce(
        (acc, user) => ramda.assoc(user.id, user, acc),
        {},
        action.payload
      ),
      userList: ramda.map(
        ramda.prop('id'),
        action.payload
      )
    }
  }
}

示例连接选择器:

connect(
  state => ({
    users: state.userList.map(id => state.userIndex[id]) // this reconstructs users in original order
  })
)(...) 

您也可以使用开源项目DataScript

An immutable in-memory database and Datalog query engine.

DataScript is meant to run inside the browser. It is cheap to create, quick to query and ephemeral. You create a database on page load, put some data in it, track changes, do queries and forget about it when the user closes the page.

DataScript databases are immutable and based on persistent data structures. In fact, they’re more like data structures than databases (think Hashmap). Unlike querying a real SQL DB, when you query DataScript, it all comes down to a Hashmap lookup. Or series of lookups. Or array iteration. There’s no particular overhead to it. You put a little data in it, it’s fast. You put in a lot of data, well, at least it has indexes. That should do better than you filtering an array by hand anyway. The thing is really lightweight.

redux 核心团队的 Javascript API. Usage example (a bit outdated). Discussion 很好。