javascript 如何为具有列表/详细信息视图和分页的应用程序选择 Redux 状态形状?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33940015/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 17:03:35  来源:igfitidea点击:

How to choose the Redux state shape for an app with list/detail views and pagination?

javascriptreduxngrx

提问by fxck

Imagine I have a number of entries(say, users) in my database. I also have two routes, one for list, other for detail(where you can edit the entry). Now I'm struggling with how to approach the data structure.

想象一下,我的数据库中有许多条目(比如用户)。我也有两条路线,一条用于列表,另一条用于详细信息(您可以在其中编辑条目)。现在我正在为如何处理数据结构而苦苦挣扎。

I'm thinking of two approaches and a kinda combination of both.

我正在考虑两种方法以及两者的结合。

Shared data set

共享数据集

  • I navigate to /list, all of my users are downloaded from api a stored in redux store, under the key users, I also add some sort of users_offsetand users_limitto render only part of the of the list
  • I then navigate to /detail/<id>, and store currently_selected_userwith <id>as the val... which means I will be able to get my user's data with something like this users.find(res => res.id === currently_selected_user)
  • updating will be nice and easy as well, since I'm working with just one data set and detail pointing to it
  • adding a new user also easy, again just working with the same list of users
  • 我导航到/list,我的所有用户都从存储在 redux 商店中的 api 下载,在密钥下users,我还添加了某种 users_offsetusers_limit仅呈现列表的一部分
  • 我然后导航到/detail/<id>,并存储currently_selected_user<id>作为VAL ...这意味着我将能够与这样的事情让我的用户的数据users.find(res => res.id === currently_selected_user)
  • 更新也会很好很容易,因为我只使用一个数据集和指向它的详细信息
  • 添加新用户也很容易,同样只需使用相同的用户列表

Now the problem I have with this approach is that, when the list of users gets huge(say millions), it might take a while to download. And also, when I navigate directly to /detail/<id>, I won't yet have all of my users downloaded, so to get data for just the one I need, I'm gonna have to first download the whole thing. Millions of users just to edit one.

现在我用这种方法遇到的问题是,当用户列表变得庞大(比如数百万)时,下载可能需要一段时间。而且,当我直接导航到 时/detail/<id>,我还没有下载所有用户,因此要获取我需要的数据,我必须首先下载整个内容。数以百万计的用户只需要编辑一个。

Separated data set

分离的数据集

  • I navigate to /list, and instead of downloading all of my users from api, I only download a couple of them, depending on what my users_per_pageand users_current_pagewould be set to, and I'd probably store the data as users_currently_visible
  • I then navigate to /detail/<id>, store currently_selected_userwith <id>as the val...and instead of searching through users_currently_visibleI simply download user's data from api..
  • on update, I'm not gonna update users_currently_visiblein any way
  • nor will I on add
  • 我导航到/list,而不是从 api 下载我的所有用户,我只下载其中的几个,这取决于我的users_per_pageusers_current_page将要设置的内容,我可能会将数据存储为users_currently_visible
  • 我然后导航到/detail/<id>,存储currently_selected_user<id>作为VAL ...,而是通过搜索users_currently_visible我只是从API下载用户的数据..
  • 更新时,我不会users_currently_visible以任何方式更新
  • 我也不会添加

What I see as possible problem here is that I'm gonna have to, upon visiting /list, download data from api again, because it might not be in sync with what's in the database, I also might be unnecessarily downloading users data in detail, because they might be incidentally already inside my users_currently_visible

我在这里看到的可能问题是,在访问时/list,我将不得不再次从 api 下载数据,因为它可能与数据库中的数据不同步,我也可能不必要地详细下载用户数据,因为顺便说一下,它们可能已经在我的体内users_currently_visible

some sort of frankenstein-y shenanigans

某种弗兰肯斯坦式的恶作剧

  • I detail, I do the same as in Separated data setbut instead of directly downloading user's data from api, I first check:
    • do I have any users_currently_visible
    • if so, is there a user with my id between them? if both are true, I then use it as my user data, otherwise I make the api call
  • same happens on update, I check if my user exists between users_currently_visibleif so, I also update that list, if not I do nothing
  • 我详细说明,我在分离数据集中做同样的事情,但不是直接从 api 下载用户的数据,我首先检查:
    • 我有吗 users_currently_visible
    • 如果是这样,他们之间是否有与我的 ID 相同的用户?如果两者都为真,则我将其用作我的用户数据,否则我进行 api 调用
  • 更新时也会发生同样的情况,我检查我的用户是否存在,users_currently_visible如果存在,我也会更新该列表,如果不是,我什么都不做

This would probably work, but doesn't really feel like it's the proper way. I would also probably still need to download fresh list of users_currently_visibleupon visiting /list, because I might have added a new one..

这可能会奏效,但并不觉得这是正确的方法。我可能还需要users_currently_visible在访问时下载新的列表/list,因为我可能已经添加了一个新列表。

Is there any fan favorite way of doing this?... I'm sure every single one redux user must have encountered the same things.

有没有粉丝最喜欢的方式来做这件事?...我相信每个 redux 用户一定都遇到过同样的事情。

Thanks!

谢谢!

回答by Dan Abramov

Please consult “real world” examplefrom Redux repo.
It shows the solution to exactly this problem.

请参考Redux 存储库中的“真实世界”示例
它显示了这个问题的解决方案。

Your state shape should look like this:

您的状态形状应如下所示:

{
  entities: {
    users: {
      1: { id: 1, name: 'Dan' },
      42: { id: 42, name: 'Mary' }
    }
  },
  visibleUsers: {
    ids: [1, 42],
    isFetching: false,
    offset: 0
  }
}

Note I'm storing entities(ID -> Object maps) and visibleUsers(description of currently visible users with pagination state and IDs) separately.

注意我分别存储entities(ID -> 对象映射)和visibleUsers(具有分页状态和 ID 的当前可见用户的描述)。

This seems similar to your “Shared data set” approach. However I don't think the drawbacks you list are real problems inherent to this approach. Let's take a look at them.

这似乎类似于您的“共享数据集”方法。但是,我不认为您列出的缺点是这种方法固有的真正问题。让我们来看看它们。

Now the problem I have with this approach is that when then list of users gets huge(say millions), it might take a while to download

现在我用这种方法遇到的问题是,当用户列表变得庞大(比如数百万)时,下载可能需要一段时间

You don't need to download all of them! Merging all downloaded entities to entitiesdoesn't mean you should query all of them. The entitiesshould contain all entities that have been downloaded so far—not all entities in the world. Instead, you'd only download those you're currently showing according to the pagination information.

您无需全部下载!合并所有下载的实体entities并不意味着您应该查询所有实体。本entities应包含已下载的所有实体到目前为止-不是世界上所有的实体。相反,您只需根据分页信息下载当前显示的内容。

when I navigate directly to /detail/, I wouldn't yet have all of my users downloaded, so to get data for just the one, I'm gonna have to download them all. Millions of users just to edit one.

当我直接导航到 /detail/ 时,我还没有下载我的所有用户,所以为了只获取一个数据,我必须下载所有用户。数以百万计的用户只需要编辑一个。

No, you'd request just one of them. The response action would fire, and reducer responsible for entitieswould merge this single entityinto the existing state. Just because state.entities.usersmay contain more than one user doesn't mean you need to download all of them. Think of entitiesas of a cache that doesn't haveto be filled.

不,您只会要求其中之一。响应动作会触发,reducer 负责entities这个单一实体合并到现有状态中。仅仅因为state.entities.users可能包含多个用户并不意味着您需要下载所有用户。想想entities为不高速缓存中被填补。



Finally, I will direct you again to the “real world” examplefrom Redux repo. It shows exactly how to write a reducer for pagination information and entity cache, and how to normalize JSON in your API responses with normalizrso that it's easy for reducers to extract information from server actions in a uniform way.

最后,我将再次引导您使用 Redux 存储库中的“真实世界”示例。它准确地展示了如何为分页信息和实体缓存编写 reducer,以及如何在 API 响应中规范化 JSON,normalizr以便 reducer 以统一的方式轻松地从服务器操作中提取信息。