如何在 Redux 中构建分页状态 [关闭]

Posted

技术标签:

【中文标题】如何在 Redux 中构建分页状态 [关闭]【英文标题】:How to structure pagination state in Redux [closed] 【发布时间】:2018-06-25 19:42:50 【问题描述】:

TL;DR:如何将分页状态存储在 Redux 存储中,给定具有大量资源的大型规范化状态树以及显示不同分页结果的多个视图?

我想知道在 Redux 存储中存储分页数据的最佳方式是什么。 This article 规定将分页信息存储为状态树中自己的子树。我同意这种方法,但在这里我不同意:文章建议通过分页资源的类型来键入分页子树,但是如果有多个视图使用不同的参数显示同一资源的分页数据怎么办?如果你按照文章的方法,你的状态树最终可能会是这样的


  pagination: 
     todos: 
       count: 1000,
       nextPageUrl: ...,
       result: [list of id's]
     users:
       count: 200,
       nextPageUrl: ...,
       result: [list of id's]

如果您有多种方式来查看同一资源,这对我来说似乎没有意义。如果在一个屏幕上有多个表格显示使用不同参数获取的待办事项怎么办?例如,一个表显示从/api/todos/?userId=1 获取的待办事项,另一个显示从/api/todos/?userId=2 获取的待办事项。

鉴于上述问题,似乎允许更灵活分页的解决方案是基于每个组件而不是每个实体存储分页状态。所以你的状态可能看起来像这样


  pagination:
    componentId:
       count: 1000,
       nextPageUrl: ...,
       result: [list of id's]
    anotherComponentId:
       count: 1000,
       nextPageUrl: ...,
       result: [list of id's]

当然,像这样存储分页结果会丢失分页内容的上下文。但这有那么大的问题吗?您如何对具有相同资源的可能多个分页结果的大型状态树进行分页?谢谢!

【问题讨论】:

我尽量不考虑实体、资源和组件,而是考虑视图。所以每个视图都可以有自己的分页。我认为它类似于上面的第二个示例,除了它不是 1:1 绑定到组件。例如,您可以有一个 TodoList 组件,该组件具有多个不同的视图(即,它显示在页面的不同位置,每个位置具有不同的上下文)。 我也是这么想的,但我不确定该组件如何在 Redux 状态下创建它的唯一分页键。如果在一个页面中放置多个 TodoList 组件,mapStateToProps 函数会是什么样子?父组件是否会为每个 TodoList 组件提供一个唯一的 key 属性,该组件在 mapStateToProps 中使用该属性来获取分页状态? 我认为每个视图都有自己的 reducer,并且使用 combineReducers 每个视图都会获得自己的状态切片。 【参考方案1】:

我认为redux-cached-pagination (Demo here) 可以帮助您解决问题。标准化的搜索结果存储在 redux 中的树中:


  standard_store: 
    pagination: 
      searchPhrase__: //results for given search params
        lastUpdateTime: 1516177824890,//last update time helps to refresh data in background
        pages:     //each page is stored. You can adjust history length
          '1': 
            isFetching: false,//each page has fetching status
            isRefreshing: false,
            isSuccess: true,
            isFailed: false,
            lastUpdateTime: 1516177824891,
            elements: [ //in 'elements' array only ids are stored. Results are normalized
              100000,
              100001,
                ...
            ]
          
        ,
        elementsCount: 800
      ,
      searchPhrase_a_:  //results for "a" search phrase
        lastUpdateTime: 1516177844624,
        pages: 
          '1': 
            isFetching: false,
            isRefreshing: false,
            isSuccess: true,
            isFailed: false,
            lastUpdateTime: 1516177844624,
            elements: [
              100001,
              100016,
              100017,
              100031,
              100044,
              100046,
              100049,
              100055,
              100056,
              100058,
              100065,
              100076,
              100077,
              100084,
              100088
            ]
          
        ,
        elementsCount: 138
      
    ,
    entities:  //here are stored entities. Entities are not duplicated. 
      '100000': 
        examData: 'BVUGUN',
        examIndexAtAll: 0,
        id: 100000
      ,
      '100001': 
        examData: 'ZR7ADV',
        examIndexAtAll: 1,
        id: 100001
      ,
        ...
    ,
    paginationParams: ,
    searchParams: 
      searchPhrase: 'al'
    ,
    currentPage: 
      pageNumber: 1
    
  

这个json是直接从redux复制过来的。 此外,您还可以获得诸如在后台刷新结果、虚拟化列表的简单使用、存储上次访问的页面等功能。 如果你想在多个列表中使用它,我建议使用reselect。

【讨论】:

这个分页树看起来更漂亮。我喜欢通过像searchPrase_a_ 这样的搜索参数来键入分页状态树的想法。那个包看起来不太适合我的设置,但我肯定会从中获得一些灵感。谢谢! 在你的情况下使用这个库有什么问题?如果您对如何简化可用性有任何想法,请随时告诉我。 对我来说一个大问题是库希望我使用 thunk 中间件,而我偏爱使用 Redux-API-middleware 样式。调用 API 与我的中间件紧密耦合。在我的动作创建者中,他们没有利用函数来调用我的 API,我不想将两者混为一谈。分页库似乎需要花点时间来熟悉。我有点难以理解它到底需要我什么,以及如何在高层次上使用它。 很难为我简化 API。目前我认为这个库过于复杂并且引入了新的复杂性(更新和管理 redux 状态)。也许更好的方法是优化服务器端搜索引擎。

以上是关于如何在 Redux 中构建分页状态 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何以正确的方式读取组件内的 redux 状态?

如何在没有 Redux 的情况下将状态保存在本地存储 React 中?

如何根据 Electron 菜单单击更改 Redux 状态?

Redux 与普通 React [关闭]

如何在 Redux/React 中处理 UI 状态 - Redux-UI?

React, Redux Application - 传递初始状态的最佳模式