Eldar Tailov
Eldar Tailov

Reputation: 378

How do I avoid repeating a code in redux + react. Example inside

I have redux selectors here in rootReducer:

export const getUser = (state) => fromUser.userGetter(state.user);
export const getUsers = (state) => fromUsers.getUsers(state.users);

// this one is just a function where 1st parameter is array, 2nd is string of ID
export const getUserNameById = (users, id) => {
    let user = ''

    if(users)
        user = users.find(user => user._id === id).name
    return user
}

// this one is selector, which does work fine
export const getUserName = createSelector([getUsers, getUser], (users, id) => {
    let user = ''

    if(users)
        user = users.find(user => user._id === id).name
    return user
});

BUT when I try do this to save line of codes:

export const getUserName = createSelector([getUsers, getUser], getUserNameById (getUsers, getUser));

it gives me error by saying getUsers.find is not an array and indeed when I console.log(getUser) it doesn't return me an array from a store, but returns me a function getUsers(state). Any ideas what should I do? Thank you!

Upvotes: 0

Views: 126

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42188

@FrozenKiwi is correct that you just need to pass the function rather than calling it.

export const getUserName = createSelector([getUsers, getUser], getUserNameById);

At runtime, the function that you pass as the second argument will be called with the values selected by the selectors of your first argument. The created selector is basically this, but with memoization:

const getUserName = (state) => getUserNameById(getUsers(state), getUser(state));

This will work assuming that getUser returns just an id. But the name implies that it might return a whole user object? So double check that.

There is a potential run-time error in your current code if users.find doesn't return a match. I suggest cleaning it up like this:

export const getUserNameById = (users, id) => {
    return (users || []).find( user => user._id === id)?.name || '';
}
  • uses an empty array if undefined (users || []) so that you can always call find. I'm doing this instead of setting a default value users = [] because some linters complain if optional arguments come before required ones.
  • uses optional chaining ?. to access name only when a user was found
  • returns an empty string if name is falsey

Upvotes: 1

Related Questions