使用分页的 NgRx Store

11

我正在寻找在服务器响应为分页时如何设计NgRx存储的方法。

如果我们只保留存储中的一页,那么使用NgRx还有什么意义呢?

如果我们为所有页面保留插槽,并在第一次调用该特定页面时在存储中填充每个页面,那么如何处理可能随每个请求不同的page_size、...查询参数。

如何处理NgRx中的过滤和排序。是否值得保留带有过多查询参数的响应?

我的当前接口如下:

res : {
    pagination: {
        page: 1,
        page_size: 25,
        total_items: 10000,
        total_pages: 400
    },
    data: [array of 25 objects]
}
2个回答

10

嗨,我将逐一回答您的问题,但您走在了正确的轨道上

如果我们只在store中保留一页,那么使用NgRx还有什么意义呢? 即使只有一页的响应,将其存储在store中的主要原因是为了在effect、另一个组件或服务中使用该搜索结果或其中一部分。例如,如果您有多行选择,则会返回一个选择器,该选择器返回所在store列表中选定的内容和处理它们的操作。另一个例子是导出按钮以创建报表,还可以用于缓存,这样如果您的搜索在选项卡内,如果您切换到另一个选项卡再返回,可以从store中收集所有数据而不必再次执行搜索。

它有很多用途,在我的经验中,将其存储在store中可以让您的生活更加轻松,但是,您完全可以将其作为本地状态存储在组件中,但是根据我的经验,随着应用程序的发展,这种方式会变得复杂,因为与之相关的越来越多的逻辑都在该组件中。 Ngrx的主要目标之一是将您的代码拆分成更易于扩展、维护和测试的部分,组件中的所有逻辑都可以工作,但是根据您的情况复杂程度而定,很难维护和测试整个逻辑。

如果我们为所有页面保留插槽,并在第一次调用特定页面时填充store中的每个页面,则如何处理可以与每个请求不同的page_size、...查询参数。

因此,如果您想缓存所有结果,请将它们全部存储在一个数组中,并使用选择器返回当前页,通过对大数组进行切片,其中开始位置是currentPage* pageSize,最后位置是currentPage* pageSize +pageSize,每次查询参数更改都必须执行新的搜索并再次存储它,除非搜索结果足够小,您可以进行内存中的搜索,这将是一个根据查询参数过滤主数组的选择器。

如何在NgRx中处理过滤和排序。值得保留具有过多查询参数的响应吗?

所以这取决于总集大小,如果总集很小,则可以在内存中完成,如果正在缓存整个结果,则可以通过由更改主数组的列触发的SortAction来排序,如果在内存中,则可以通过选择器来过滤主数组,根据查询参数。

现在,如果搜索太大,通常最好由后端进行搜索,并且如果他们进行了搜索,则他们也必须进行排序,因此现在任何排序或查询参数更改都将触发一个新的操作,以执行搜索并缓存结果,在这里,您可以仅存储一页或请求3页,并使用切片选择器返回所需的页面,或者如果页面不在缓存中,则返回一个标志,以便触发另一个查询。

根据分页控件的不同,你可以实现更聪明的缓存。如果你能跳过x页,那么之前我描述的方法是最好的。但是,如果你只有“下一页”和“上一页”这样的分页控件(例如使用cdk虚拟滚动),那么每次获取结果后,你可以将其附加到当前结果中,因此向后翻页时全部使用缓存,向前翻页只需要两页,假设你请求了3页。
如果你想知道我为什么总是提到缓存3页,那么有研究表明,在分页搜索中,超过90%的用户不会超过3页,但这可能不适用于你。此外,如果你多次实现这个功能,你会发现一些逻辑可以提取到函数中,比如对数组中对象的字段进行排序或者页面切片。我一直计划创建类似ngrx entity的东西,但它更专注于搜索、排序和分页,但尚未完成。希望这能帮到你。

这篇文章已经有点老了,但是你提到了Ngrx Entity。你认为将所有曾经请求过的内容添加并保留在store中的策略如何?这可能无法避免服务器请求,但至少可以避免重新渲染,如果数据集不太大,那么内存也不应该成为问题,对吧? - trueunlessfalse
2
是的,只要数据集不太大,那是可行的方法。但是,如果您在存储中存储了2000个项目,它不会占用太多内存,但在渲染时可能会占用很多内存,因此我仍然使用分页进行渲染,或者使用无限滚动。 - Gabriel Guerrero

1
我可以帮助你翻译以下内容:

不确定是否有必要存储pageSize,我们可以从当前页面对象数量中获取它。您可以将页面标识符的实际数据存储在一个单独的属性中,将提取的所有数据存储在另一个属性中,并使用keys属性控制元素的顺序。返回具有现有数据的页面后,只需更新日期以进行同步。

您存储

export interface State {
  page: number;
  totalPages: number;
  totalItems: number;
  keys: string[];
  data: {
    [id: string]: DataInterface;
  };
}

使用选择器获取数据

export const getCurrentPageDataState = createSelector(getDataState, state => state.keys.map(key => state.data[key]);

我不确定我是否理解了你的意思。这似乎是NgRx Entity的实现。它是否在存储中仅保留一页?例如,如果我点击第2页,第1页的内容会在存储中被替换吗?如果我先点击第1页,然后是第4页,最后是第7页,如何保持存储内容的一致性? - ashil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接