想象一下,我的数据库中有很多条目(例如用户)。我还有两个路由,一个用于列表,另一个用于详细信息(您可以在其中编辑条目)。现在我正在努力解决如何处理数据结构问题。
我正在考虑两种方法和两种方式的组合。
/list
,我的所有用户都从存储在redux商店的api下载,在密钥users
下,我还添加了某种users_offset
和{{1仅呈现列表的一部分users_limit
,并将/detail/<id>
与currently_selected_user
一起存储为val ...这意味着我将能够以这样的方式获取用户的数据{{1 }} 现在我用这种方法遇到的问题是,当用户列表变得庞大(比如数百万)时,下载可能需要一段时间。而且,当我直接导航到<id>
时,我还没有下载所有用户,所以为了获得我需要的数据,我将不得不首先下载整个内容。数以百万计的用户只需编辑一个。
users.find(res => res.id === currently_selected_user)
,而不是从api下载我的所有用户,而是根据我/detail/<id>
和/list
的设置,我只下载了几个用户,我可能会将数据存储为users_per_page
users_current_page
,将users_currently_visible
存储为/detail/<id>
作为val ...而不是搜索currently_selected_user
我只是从api下载用户的数据。 <id>
我认为这里可能存在的问题是,在访问users_currently_visible
时,我将不得不再次从api下载数据,因为它可能与数据库中的内容不同步,我也可能是不必要地详细下载用户数据,因为它们可能偶然已经在我的users_currently_visible
/list
users_currently_visible
之间,如果是,我也会更新该列表,如果不是我什么都不做这可能会奏效,但并不觉得这是正确的方法。在访问users_currently_visible
时,我可能仍需要下载users_currently_visible
的新列表,因为我可能添加了一个新列表..
有没有粉丝最喜欢这样做的方式?...我确信每一个redux用户都必须遇到同样的事情。
谢谢!
答案 0 :(得分:75)
请咨询Redux repo的“real world” example 它显示了解决这个问题的方法。
你的状态应如下所示:
{
entities: {
users: {
1: { id: 1, name: 'Dan' },
42: { id: 42, name: 'Mary' }
}
},
visibleUsers: {
ids: [1, 42],
isFetching: false,
offset: 0
}
}
注意我将分别存储entities
(ID - &gt;对象地图)和visibleUsers
(当前可见用户的分页状态和ID说明)。
这与您的“共享数据集”方法类似。但是我不认为你列出的缺点是这种方法固有的真正问题。我们来看看它们。
现在我用这种方法遇到的问题是,当用户列表变得庞大(比如数百万)时,下载可能需要一段时间
您无需下载所有内容!将所有下载的实体合并到entities
并不意味着您应该查询所有这些实体。 entities
应包含已下载的所有实体到目前为止 - 不是世界上所有实体。相反,您只能根据分页信息下载您当前正在显示的内容。
当我直接导航到/ detail /时,我还没有下载所有用户,所以为了获得这些用户的数据,我将不得不全部下载。数以百万计的用户只需编辑一个。
不,你只要求其中一个。响应操作将触发,负责entities
的reducer将此单个实体合并到现有状态。仅仅因为state.entities.users
可能包含多个用户并不意味着您需要下载所有这些用户。将entities
视为未填充 的缓存。
最后,我将再次指导您从Redux回购中找到“real world” example。它显示了如何为分页信息和实体缓存编写减速器,以及how to normalize JSON in your API responses with normalizr
,以便减速器可以轻松地以统一的方式从服务器操作中提取信息。
答案 1 :(得分:0)
在标准化实体之前,我还使用过normalizr
方法,但是问题在于这需要手动操作。
如果您了解GraphQL世界中的Apollo,则可能知道它支持自动规范化,因此给定对象的数据不会存储在多个位置。此外,它们还支持自动更新,如果您的服务器响应的对象具有相同的ID但具有更新的属性,则Apollo会识别它并在多个位置更新该对象。
但是,为什么只为GraphQL保留这种奢侈品?由于这个原因,我实现了https://pypi.org/project/Eel/库,该库支持对任何API,REST,GraphQL,Firebase等进行自动归一化。它是如何工作的?假设您有一个图书清单和详细的端点。要与他们进行交流,您只需要分派Redux这样的操作即可:
const fetchBooks = () => ({
type: FETCH_BOOKS,
request: { url: '/books' },
meta: { normalize: true },
});
const fetchBook = id => ({
type: FETCH_BOOK,
request: { url: `/books/${id}` },
meta: { normalize: true },
})
现在,要在两个地方都更新一本书的书名,我们只需这样做:
const updateBookTitle = (id, newTitle) => ({
type: UPDATE_BOOK_TITLE,
request: { url: `books/${id}`, method: 'PATCH', data: { newTitle } },
meta: { normalize: true },
})
如果您对这种方法感兴趣,请阅读redux-requests