如何在redux中为每个类别构建延迟加载项的状态

时间:2016-08-13 10:08:29

标签: redux react-redux

  

我们说我有一个api端点/categories,它返回一个类别数组

[
  {
    id: '1'
    name: 'category-1'  
  },
  {
    id: '2'
    name: 'category-2'  
  }
  ...
]

和端点,用于检索类别items/:categoryId中返回项目数组

的项目
[
  { id: '1', name: 'item-1' },
  { id: '2', name: 'item-2' }
  ...
]

在UI上,我显示了一个类别列表,我可以展开这些类别并延迟加载项目列表。 我希望能够扩展多个类别,并且需要能够添加,编辑和删除项目。

为这样的场景组织状态的最佳方法是什么?

目前我的州看起来像这样:

{
  entities: {
    categories: {
      '1': {
        id: '1'
        name: 'category-1'  
      },
      '2': {
        id: '2'
        name: 'category-2'  
      },
      ...
    },
    items: {
      '1': {
        id: '1'
        name: 'item-1'  
      },
      '2': {
        id: '2'
        name: 'item-2'  
      },
      ...
    }
  },

  categories: {
    ids: ['1', '2', ...],
    isFetching: bool
    error: null
  },
  itemsByCategory: {
    '1': {
      ids: ['1', '2',...]
      isFetching: bool,
      error: null
    }
    ...
  }
} 

itemsByCategory中,键是类别的ID,如果尚未加载给定类别的项目,则itemsByCategory上的密钥将不存在。

此解决方案有效,但有一些缺点。为了删除项目,我必须传递两个键(项目ID和类别ID)而不是项目ID(我也可以通过所有类别来查找项目,但它可能会变慢)。

  

我也不满意检查是否加载了给定类别的项目。   (首先我要检查是否在itemsByCategory上定义了具有类别ID的键),因此我的选择器变得有点复杂。

有没有更好的方法来塑造这种情况的状态?

2 个答案:

答案 0 :(得分:0)

为了从类别中删除项目,需要传递类别ID和项目ID。这是因为它们是连接在一起的。

从您的特定用例中抽象出来,每次您想要更改两个逻辑实体之间的连接(建立新的逻辑实体或破坏现有实体)时,您必须以某种方式解决该连接。可以这样做:

  1. 直接:提供两个实体的ID。
  2. 间接地:只提供其中一个的id,并从某种地图中获取另一个的id。
  3. Hacky:通过某些规则使实体id彼此可导出。
  4. 回到您的用例意味着:

    1. 您不喜欢的方式:提供类别ID以及项目ID。
    2. 迭代类别以查找哪个包含给定项目,或在您的州中引入categoryByItem地图,或在每个categoryId中包含items字段。
    3. 更改项ID以在其中保留适当的类别ID:item.id = item.id + '/' + category.id。然后,只需将项目ID分成'/'即可获得类别。
    4. 关于检查itemsByCategory是否存在类别ID键的问题,为什么不填充此对象以及填充entities.categories对象?每次加载新类别(例如,使用id categoryId)时,在itemsByCategorycategoryId下创建一个空对象(或非空,但形状指示已卸载状态)钥匙。

      另一种可能性,特别是如果你发现自己经常进行null检查,就是使用idx helper function from Facebook.有了它的帮助你的选择器会是这样的:

      const isItemsLoaded = (state, categoryId) => idx(state, _ => _.itemsByCategory[categoryId].isLoaded);
      

答案 1 :(得分:0)

如果categoryitem的属性,则每个项目都应具有categoryId属性,仅存储对其的引用,并避免在任何地方复制类别。如果API调用返回的项目不包含您可以在获得API结果后立即分配的类别,因为您知道该类别,因为您已经使用它来首先检索项目

categoriesitemsByCategory都会通过存储元素的ID来复制entites中已有的信息,您不需要存储这些信息。

如果您懒得加载的唯一内容是每个类别的项目,请在categories中创建一系列已加载的类别,以检查您是否必须进行API调用。

itemsByCategory对我来说看起来毫无用处,除非您还懒得加载有关每件商品的更多信息。

我不担心循环遍历所有项目以检索与每个类别对应的项目,只要您只对那些已展开的类别执行此操作即可。毕竟React意味着以这种方式使用并且非常擅长它。如果您遇到性能问题,可能是因为您正在更改父组件并强制重新呈现所有列表。

如果所有这些都失败了,您只需要渲染太多数据,并且可能会重新考虑UI并添加某种类型的分页。 另一个选项是在折叠类别后从entities清除项目,并从已加载的类别中删除该类别,但这可能会对您的用户产生负面影响。