3

使用工厂选择器模式const selectA = (id: number) => createSelector(...),我有一个实例,我想在另一个选择器(遍历 ID 数组)中重用此选择器,但我不知道在调用createSelector.

所以我有一个选择器,每当我想获得组件 A 的一部分状态时,我都会使用它。

const selectA = (id: number) =>
    createSelector(
        selector1.selectEntityMap,
        selector2.selectEntityMap,
        selector3ById(id), 
        (
        thing1, 
        thing2, 
        thing3
        ) => {
            return ...
       });

现在我想为数组中的每个项目获取组件 A 的列表。

const selectListOfA = (ids: number[]) =>
    createSelector(
    selectA, 
    (selectorA) => {
        return ids.map((id) => selectorA(id));
    });

问题是selectA,它现在是一个工厂选择器,需要一个参数,但调用时我不知道它createSelector

我可以通过在工厂中创建另一个工厂来编译代码 const selectAFactory = () => selectA;

然后引用新工厂中的createSelector

const selectListOfA = (ids: number[]) =>
    createSelector(
    selectAFactory, <<< here 
    (selectorA) => {
        return ids.map((id) => selectorA(id));
    });

但是,当然,现在发生的是选择器正在返回一个MemoizedSelector[].

这种模式似乎不应该这么复杂,人们不是以这种方式重用他们的选择器吗,我错过了什么?

4

1 回答 1

0

返回的函数selectA是一个标准函数,没有什么神奇之处,正如这篇博文中解释的那样:https ://dev.to/zackdrose/ngrx-fun-with-createselectorfactory-hng

这意味着selectListOfA可以简单地调用从selectA每个 id 返回的函数,并且将返回组件 A 的状态切片数组:

export const selectListOfA = (ids: number[]) =>
  createSelector(
    (state) => state,
    (state) => ids.map((id) => selectA(id)(state))
  );

这可以按预期工作,但是由于每次商店中的任何内容发生更改(为每个 id 重新创建选择器)时都会执行投影仪功能,因此该解决方案将存在重大性能问题。

我们也可以将代码简化为同样糟糕的性能:

const selectListOfA = (ids: number[]) =>
  (state) => ids.map(
    (id: number) => selectA(id)(state)
  );

如果我们改为提供一个选择器数组作为createSelector调用的输入,那么 Ngrx 将能够正确确定何时必须重新评估selectA选择器:

const selectListOfA = (ids: number[]) =>
  createSelector(
    ids.map((id) => selectA(id)), // This results in an array of selectors
    (...resultArr) => resultArr
  );

但是,Typescript 会抱怨,因为 createSelector 方法没有为可变长度数组声明匹配的重载,因此我们需要放宽数组的输入类型 (to any) 并指定 的返回类型selectListOfA

因此,问题的答案是:

  const selectListOfA = (ids: number[]) =>
  (createSelector(
    ids.map((id) => selectA(id)) as any,
    (...resultArr) => resultArr
  ) as (state) => string[]);
于 2021-12-27T15:26:49.710 回答