Note: This will be a series of posts around how I moved from custom built reducers and state management with NgRx to use the NgRx Entity library.
In NgRx Entities: Namespaces with TypeScript I previously wrote how I was changing up my reducers to use the Entity library from NgRx and utilizing TypeScript to my advantage. The next step was to update the selectors I had setup to use the new namespace and adapter.
A great reference book that goes deeper into this topic: Architecting Angular Applications with Redux, RxJS, and NgRx
What was there before
Again, still as an example with using books, here is a snippet code of what the selector file looked like.
1 | // store/selectors/books.selectors.ts |
2 | |
3 | const selectBooksState = (state: AppState) => state.books; |
4 | |
5 | export const selectBooks = createSelector( |
6 | selectBooksState, |
7 | (state: BooksState) => state.books, |
8 | ); |
9 | |
10 | export const selectSelectedBook = createSelector( |
11 | selectBooksState, |
12 | (state: BooksState) => state.selectedBook, |
13 | ); |
Here we have two selectors:
selectBooks
which will return the full collection of the books in the storeselectSelectedBook
which returns the individual selected book from the store of books
Moving to the createFeatureSelector
Since the entity use with NgRx creates a more complex store object, moving to the createFeatureSelector
needed to happen. This method from the NgRx store library creates a specific key on the store for your feature so that an optimization happens during the selection process.
1 | // store/selectors/books.selectors.ts |
2 | |
3 | export const selectBooksState |
4 | = createFeatureSelector<BooksStore.State>('books'); |
5 |
With this in place, the selector can access the store quicker based on the shape created by the entity setup:
1 | // store shape |
2 | { |
3 | books: { |
4 | ids: [1, 2, ...], |
5 | entities: [ |
6 | { id: 1, title: 'The Shinning' }, |
7 | { id: 2, title: 'It' }, |
8 | ... |
9 | ], |
10 | selectedBook: null, |
11 | } |
12 | } |
Now I can change up the rest of the selectors to use the adapter
selectors exported from the BooksStore
that was exported and also change the selectSelectedBook
to look into the entities array.
1 | // store/selectors/books.selectors.ts |
2 | |
3 | export const selectBooks = createSelector( |
4 | selectBooksState, |
5 | BooksStore.selectAll, |
6 | ); |
7 | |
8 | export const selectSelectedBook |
9 | = (bookId: number) => createSelector( |
10 | selectBooksState, |
11 | (state: BooksStore.State) => state.entities[bookId], |
12 | ); |
Again, there tends to be extra code with this move, but in the long run, the changes made to the reducers make up for it all, which I will dive into next.