Селекторы NGRX: фабричный селектор в другом селекторе без опоры в методе createSelector

Использование заводского шаблона селектора const selectA = (id: number) => 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, который теперь является заводским селектором, ожидает параметр, но я не знаю его при вызове.

Я могу получить код для компиляции, создав еще одну фабрику на фабрике const selectAFactory = () => selectA;

Затем укажите новую фабрику в createSelector

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

Но, конечно, сейчас происходит то, что селектор возвращает список MemoizedSelector[].

Этот шаблон не кажется таким сложным, люди не используют повторно свои селекторы таким образом, что мне не хватает?

1 ответ

Функция, возвращаемая является стандартной функцией, т.е. в ней нет ничего волшебного, как хорошо объяснено в этом сообщении в блоге: https://dev.to/zackderose/ngrx-fun-with-createselectorfactory-hng

Это означает, что можно просто вызвать функцию, возвращаемую из для каждого идентификатора, и будет возвращен массив срезов состояния для компонента A:

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

Это работает, как и ожидалось, но поскольку функция проектора будет выполняться каждый раз, когда что-либо изменяется в хранилище (воссоздание селектора для каждого идентификатора), это решение будет иметь серьезные проблемы с производительностью.

С тем же успехом мы могли бы упростить код до такой же низкой производительности:

      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 не имеет соответствующей перегрузки, объявленной для массива переменной длины, поэтому нам нужно ослабить входной тип массива (чтобы any), а также указать тип возвращаемого значения selectListOfA.

Ответ на вопрос такой:

        const selectListOfA = (ids: number[]) =>
  (createSelector(
    ids.map((id) => selectA(id)) as any,
    (...resultArr) => resultArr
  ) as (state) => string[]);
Другие вопросы по тегам