Search code examples
javascriptreactjsreduxreselect

Reselect selectors structure


i have the following example structure..

userId: {
  savedEvents: {
     eventId: true,
     eventId: true,
     eventId: true,
  },
  organisedEvents: {
     eventId: true,
     eventId: true,
     eventId: true,
  },
  attendingEvents: {
     eventId: true,
     eventId: true,
     eventId: true,
  }
}

I am using reselects createSelector method to try and chain selectors for memory optimisations and re-use of business logic..

For example :-

userOrganisedEventsSelector

Returns a list of organised event ids.

activeUserOrganisedEventsSelector

Uses the output of userOrganisedEventsSelector with a set of filters have been applied

sortedActiveUserOrganisedEventsSelector 

Sorts the output of activeUserOrganisedEventsSelector

The three above methods accept a prop object containing userId, from which it can then determine the organised event.

The problem :-

  1. I want the same functionality for all three event types (savedEvents, organisedEvents and attendingEvents)

  2. In some scenarios i would like the userId to be provided by props, other times i need to use a userId from state.

I am looking for help or advise on how to achieve this, without creating 30 odd functions, while keeping the benefits of memorising via reselect.


Solution

  • I'd suggest you to give re-reselect a try. It's a tiny reselect wrapper I wrote when I found my self writing almost identical selectors in a scenario similar to yours.

    It will allow you to not repeat selectors code and to better manage selectors caching when passing different params (eg, your userID).

    Here a few line of pseudocode, just you get you on the right track:

    import createSelector from 'reselect';
    import createCachedSelector from 're-reselect';
    
    // Normal reselect selector:
    // getUserEvents(state, userId)
    const getUserEvents = createSelector(
      state => state.events
      (state, userId) => userId,            // Get user from state if userId not provided
      (events, userId) => events[userId],   // Return user's events
    );
    
    // Cached re-reselect selector (cached by eventType):
    // getUserEventsOfType(state, userId, eventType = 'ALL')
    const getUserEventsOfType = createCachedSelector(
      getUserEvents,                        // Get events from getUserEvents
      (state, userId, eventType = 'ALL') => eventType,
      (userEvents, eventType) => userEvents[eventType]  // Just pseudo code!
    )(
      // Keep memoization when calling selector with different eventType
      (state, userId, eventType = 'ALL') => eventType,
    );