Search code examples
ngrxreselectngrx-store

Why the reselect createSelector necessary in this @ngrx example?


What does the following code snippet do? It is taken from this file.

export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading);

The fromCollection.getLoading has only either true or false value, so can there be any optimization achieved by using the createSelector?

in

export const getCollectionLoaded = createSelector(getCollectionState, fromCollection.getLoaded);

export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading);

export const getCollectionBookIds = createSelector(getCollectionState, fromCollection.getIds);

Solution

  • According to the example app's comments:

    /**
     * Every reducer module exports selector functions, however child reducers
     * have no knowledge of the overall state tree. To make them useable, we
     * need to make new selectors that wrap them.
     **/
    

    For example in reducers/collections.ts the selectors at the bottom of the file only reference the collection slice:

    export const getLoaded = (state: State) => state.loaded;
    export const getLoading = (state: State) => state.loading;
    export const getIds = (state: State) => state.ids;
    

    These collection selectors can't be used with state.select() because state.select expects to work with the whole AppState. Therefore in the reducers/index.ts the selector is then wrapped with another selector so that it does work with the whole AppState:

    export const getCollectionLoading = createSelector(getCollectionState, fromCollection.getLoading);
    

    Back to your question: why is it necessary to use reselect for this. Reselect in this case isn't providing any optimizations. So the main purpose of reselect is that it provides the ability to compose selectors together.

    By using this composition feature we can make collections.ts only have selectors for the collections slice. Then in index.ts we can have selectors at the AppState level. Furthermore we can have selectors that work across different slices of the store such as this one:

    /**
      * Some selector functions create joins across parts of state. This selector
      * composes the search result IDs to return an array of books in the store.
      */
    export const getSearchResults = createSelector(getBookEntities, 
    getSearchBookIds, (books, searchIds) => {
      return searchIds.map(id => books[id]);
    });