3

I am trying to call a combined selector from redux-saga. The idea is that I have two drop downs. Choices in first drop down will filter the appropriate values in second drop down, i.e. my combined selector will filter out some non relevant values, so they will not be shown in second drop down:

1) I have two selectors, firstSelector and secondSelector

// firstSelector returns {"Cat":["black","white"],"Dog":["grey"]}
const firstSelector= () =>
  createSelector(selectPage, substate => substate.firstDropDown);

// secondSelector returns ["black","grey"]
const secondSelector= () =>
  createSelector(selectPage, substate => substate.secondDropDown);

2) I combine those in combined selector (which should return ["black", "grey"], i.e. "white" is filtered out)

const filterBySelection = (firstSelector, secondSelector) =>
  createSelector(
    [
      firstSelector, 
      secondSelector, 
    ],
    (first, second) => {
      const filteredValues = Object.keys(first).reduce(
        (r, k) => r.concat(first[k]),
        [],
      );
      return second.filter(val => filteredValues.indexOf(val) >= 0);
    },
  );

3) But how can I call filterBySelection in redux-saga? I tried:

const filteredValues = yield select(
  filterBySelection,
  firstSelector,
  secondSelector,
);

And

const filteredValues = yield select(
  filterBySelection(firstSelector, secondSelector)()
);

And

const filteredValues = yield select(
  filterBySelection(firstSelector, secondSelector)
);

But those ways do not work.

Though, I can call firstSelector or secondSelector, i.e. works:

const firstData= yield select(firstSelector());

Someone can say that I can simply do the below in redux-saga:

const first = yield select(firstSelector());
const second = yield select(secondSelector());
const filtered = Object.keys(first).reduce(
  (r, k) => r.concat(first[k]),
  [],
);
const secondFiltered = second.filter(
  val => first.indexOf(val) >= 0,
);

But that will not memoize and the idea is to memoize.

So is it possible to use a memoized selector in redux-saga?

Best Regards

user1665355
  • 3,324
  • 8
  • 44
  • 84
  • I think you can drop array in createSelector, just pass the subSelectors as arguments – Kasia Feb 26 '19 at 11:48
  • ```const filterBySelection = (firstSelector, secondSelector) => createSelector( firstSelector, secondSelector, (first, second) => { const filteredValues = Object.keys(first).reduce( (r, k) => r.concat(first[k]), [], ); return second.filter(val => filteredValues.indexOf(val) >= 0); }, );``` – Kasia Feb 26 '19 at 11:49

2 Answers2

1

You seems to miss call the function to return the selector. So, either:

a)

const filterBySelection = (firstSelector, secondSelector) =>
  createSelector(
    [
       firstSelector(), // <- parentheses 
       secondSelector(), // <- parentheses 
     ], ... )

then: const filteredValues = yield select( filterBySelection(firstSelector, secondSelector) );

b) pass selectors correctly

const filteredValues = yield select(
  filterBySelection(firstSelector(), secondSelector())
);

c) define firstSelector and secondSelector without function (perhaps the most true way):

const firstSelector = 
  createSelector(selectPage, substate => substate.firstDropDown);

const secondSelector = 
  createSelector(selectPage, substate => substate.secondDropDown);

then

const filteredValues = yield select(
  filterBySelection(firstSelector, secondSelector)
);

Hope it helps.

Alejandro
  • 5,834
  • 1
  • 19
  • 36
1

I would go with something like this

  createSelector(
    firstSelector, 
    secondSelector, 
    (first, second) => {
      const filteredValues = Object.keys(first).reduce(
        (r, k) => r.concat(first[k]),
        [],
      );
      return second.filter(val => filteredValues.indexOf(val) >= 0);
    },
  );```
Kasia
  • 1,665
  • 1
  • 10
  • 16
  • That is my selector exactly. It is not the question / problem. – user1665355 Feb 26 '19 at 12:29
  • I'm saying, that you should drop the array – Kasia Feb 27 '19 at 07:10
  • and with dropping the array you don't need to use parentheses () – Kasia Feb 27 '19 at 07:12
  • Thank you! I found this very helpful. I combined a separate selector into the main one and everything worked. Before the separate selector was causing issues (search term filtering as well as separate radio filters). – user.io Jul 22 '20 at 14:22