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

Mic*_*hał 9 redux react-redux

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

[
  {
    id: '1'
    name: 'category-1'  
  },
  {
    id: '2'
    name: 'category-2'  
  }
  ...
]
Run Code Online (Sandbox Code Playgroud)

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

[
  { id: '1', name: 'item-1' },
  { id: '2', name: 'item-2' }
  ...
]
Run Code Online (Sandbox Code Playgroud)

在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
    }
    ...
  }
} 
Run Code Online (Sandbox Code Playgroud)

itemsByCategory键中是类别的ID,如果尚未加载给定类别的项目,则键不会存在itemsByCategory.

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

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

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

fku*_*kov 0

对于需要传递类别 id 和项目 id 以便从类别中删除项目,我们无能为力。这是因为它们是相互联系的。

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

  1. 直接:提供两个实体的 ID。
  2. 间接:仅提供其中一个的 id,并从某种地图中获取另一个的 id。
  3. Hacky:使实体 id 可通过某些规则从另一个派生出来。

回到你的用例,这意味着:

  1. 您不喜欢的方式:提供类别 ID 和项目 ID。
  2. 要么迭代类别以查找哪个类别包含给定项目,要么categoryByItem在您所在的州引入地图,或者categoryId在您的每个items.
  3. 更改项目 id 以在其中保留适当的类别 id item.id = item.id + '/' + category.id:。然后只需用“/”分割项目 ID 即可获得类别的 ID。

关于检查类别 id 键是否存在的问题itemsByCategory,为什么不只在填充entities.categories对象的同时填充此对象呢?每次加载新类别(比方说, id )时,在该键下categoryId创建一个空对象(或不是空的,但具有指示卸载状态的形状)。itemsByCategorycategoryId

另一种可能性null是使用Facebook 的 idx 辅助函数,尤其是在您发现自己检查过于频繁的情况下。有了它的帮助,您的选择器将如下所示:

const isItemsLoaded = (state, categoryId) => idx(state, _ => _.itemsByCategory[categoryId].isLoaded);
Run Code Online (Sandbox Code Playgroud)