Skip to content

Store: Add "combineSelectors" function to provide more intuitive way to combine states #2838

@brandonroberts

Description

@brandonroberts

Creating selectors is done in two primary ways:

  • Selecting a feature state by its key, and building smaller state selectors from it
const selectProductsState = createFeatureSelector('products');

const selectCurrentProductId = createSelector(
  selectProductsState,
  state => state.currentProductId
);

const selectAllProducts = createSelector(
  selectProductsState,
  state => state.collection
);

And doing the same with another slice of state

const selectCategoriesState = createFeatureSelector('categories');

const selectCurrentCategoryId = createSelector(
  selectCategoriesState,
  state => state.currentCategoryId
);

const selectAllCategoriesEntities = createSelector(
  selectCategoriesState,
  state => state.entities
);
  • Creating a selector that combines other selectors
const selectCurrentProductWithCategory = createSelector(
  selectAllProducts,
  selectAllCategoriesEntities,
  (products, categoryEntities) => {
    return products.map(product => {
      return {
        ...product,
        category: categoryEntities[product.categoryId] ? categoryEntities[product.categoryId].name : ''
      };
    });
  };
);

From seeing various trends through code reviews, its not very apparent that createSelector can be used to create selectors, and combine selectors. Developers usually end up combining these states using observables, which can be expensive.

This change proposes an alias to createSelector named combineSelectors.

const selectAllProducts = createSelector(
  selectProductsState,
  state => state.collection
);

const selectAllCategoriesEntities = createSelector(
  selectCategoriesState,
  state => state.entities
);

const selectCurrentProductWithCategory = combineSelectors(
  selectAllProducts,
  selectAllCategoriesEntities,
  (products, categoryEntities) => {
    return products.map(product => {
      return {
        ...product,
        category: categoryEntities[product.categoryId] ? categoryEntities[product.categoryId].name : ''
      };
    });
  };
);

It's not a different API functionally, but something similar to createReducer and combineReducers, where we have a defined API to create vs combine selectors. This would encourage developers to combine states together in a standardized way.

Other information:

If accepted, I would be willing to submit a PR for this feature

[ ] Yes (Assistance is provided if you need help submitting a pull request)
[ ] No

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions