Skip to content

Instantly share code, notes, and snippets.

@abhiaiyer91
Last active April 29, 2022 06:00
Show Gist options
  • Save abhiaiyer91/aaf6e325cf7fc5fd5ebc70192a1fa170 to your computer and use it in GitHub Desktop.
Save abhiaiyer91/aaf6e325cf7fc5fd5ebc70192a1fa170 to your computer and use it in GitHub Desktop.
Redux Selector Pattern

Redux Selector Pattern

Imagine we have a reducer to control a list of items:

function listOfItems(state: Array<Object> = [], action: Object = {}): Array<Object> {
  switch(action.type) {
    case 'SHOW_ALL_ITEMS':
      return action.data.items
    default:
    return state;
  }
}

Where Items looks like this:

type ItemType = {
  id: string,
  text: string,
  completed: boolean
};

Today we mapStateToProps for all incomplete items like this:

function mapStateToProps(state) {
  return {
    incompleteItems: state.listOfItems.filter((item) => {
      return !item.completed
    });
  }
}

The problem with this approach

There are a couple problems with this approach as the application grows.

  1. The implementation of incompleteItems may change.
  2. Computation logic occurs in mapStateToProps
  3. Can't memoize the values of incompleteItems

The Solution

After talking with Dan Abramov (founder of Redux) he has been preaching the colocation of functions called selectors with your reducers.

What is a selector?

  1. Selectors can compute derived data, allowing Redux to store the minimal possible state.
  2. Selectors are composable. They can be used as input to other selectors.

Let's turn our filter into a selector.

Place your selectors near the Redux reducer!!!

function listOfItems(state: Array<Object> = [], action: Object = {}): Array<Object> {
  switch(action.type) {
    case 'SHOW_ALL_ITEMS':
      return action.data.items
    default:
    return state;
  }
}

function getIncompleteItems(state: Object): Array<Object> {
  return state.listOfItems.filter((item) => {
    return !item.completed
  });
}

And we update our mapStateToProps function:

function mapStateToProps(state) {
  return {
    incompleteItems: getIncompleteItems(state)
  }
}

Now we can reuse this logic across many components mapping this exact state! We can unit test it as well! More importantly we can now memoize this state with reselect

Next Steps:

Now don't go and rewrite all your mapFns! We'll use this pattern going forward on new reducers and Redux connect components.

@aruprakshit
Copy link

Thanks for putting it together.

@pkhodaveissi
Copy link

short and comprehensive, thanks

@aminsoraya
Copy link

I want to send an array of numbers to the mapStateToProps to filter it according to these numbers but how can I do that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment