How to manage a selector that accepts arguments with yield select?

Viewed 717

I have a React application where I'm using Redux and Redux-Saga and Reselect as selector library (with Immer to handle the immutability of the Redux state). I'm writing this question because I'd like to understand if my approach to handle the selector with argument is fully correct.

I personally prefer to avoid the yield select into the sagas because I'd like to keep the middleware not depend on the Store's state, but I have legacy code that has sagas with yield select in it.

Here below the code that I have to write to implement my selector and invoke him into the component and into the saga. I got the selector implementation from the Reselec doc.

// selectors.js: Selector implementation
const makeGetPerson = createSelector(
  getPersonsList,
  (state, id) => id,
  (persons, id) => persons.find((person) => person.id === id)
);

// components.js: if I have to use the selector into a component
const person = useSelector((state) => makeGetPerson(state, id))


// saga.js: if I have to use the selector into a saga
const persons = yield select(getPersonsList)
const person = persons.find((person) => person.id === id)

At the moment from the saga I have to use the selector that return the list of element and manually filter them. Is there a way to do something like yield select((state) => getPersonsList(state, id)) into the a saga ? Is there any other approach that I'm missing ?

2 Answers

You could also make the createSelectPersonById a curry:

const createSelectPersonById = id => createSelector(
  getPersonsList,
  (persons) => persons.find((person) => person.id === id)
);
// components
const person = useSelector(createSelectPersonById(id))
//saga
const person = yield select(createSelectPersonById(id));

In the select person by id you are just returning state and not a new object but if you did return a new object every time you could use useMemo in your component so you don't get needless re renders when unrelated actions are dispatched:

//selector returning new object every time it is executed
const createSelectPersonById = (id) =>
  createSelector(getPersonsList, (persons) => {
    const person = persons.find(
      (person) => person.id === id
    );
    //returning a new object reference every time
    return {
      ...person,
      fullName:formatFullName(person)
    }
  });
//in components
const selectPersonById = React.useMemo(
  ()=>createSelectPersonById(id),
  [id]//selector only re created when id changes
)
const person = useSelector(selectPersonById);
//in saga nothing changes, no need to memoize:
const person = yield select(createSelectPersonById(id));

More info on how and why I make parameterized selectors a curry in React can be found here

Related