Skip to main content

Angular NgRx: A Simple Selector

Greetings!

In this third installment of our simple NgRx series we are going to have a look at selectors. As this is again confusing at first, let's use our simple message string to learn this. For the simplicity, i'm not using any actions in this example.

Comple code can is here https://github.com/slmanju/ngrx-at-slmanju/tree/main/ngrx-hello-selector

What we need

  • Store initial value
  • Create reducer to get initial value
  • Register the reducer
  • Create selector(s)
  • Read, change values from the component

Generate the Project

ng new ngrx-hello-selector --routing=false --style=css
cd ngrx-hello-selector/
ng add @ngrx/store@latest
ng serve

Register the Reducer

As in our first article, we will just store a string value in our store. Then register the reducer to read it. If you haven't read it, here is the code.
ngrx-hello-selector/src/app/app.reducer.ts
const initialState = 'Whatever you are, be a good one.';

const _messageReducer = createReducer(
  initialState
);

export function messageReducer(state: string = initialState, action: Action) {
  return _messageReducer(state, action);
}
In app.module.ts
StoreModule.forRoot({
  message: messageReducer
}, {}),
As usual, note that since our value is a string and reducer key is message, this data structure will be
{ message: string }
This is an important point to create/use selectors.

How to use Selectors?

Now now.., this beats me!! we have multiple ways to 'select' our stored values.
As I explained above, since our data structure is { message: string }, our Store will be
Store<{ message: string }>
Hence we have 'select',
store.select('message')
store.select((state) => state.message) // 2nd option
store.select(selector) // this is what we are going to do

Create Selector

Again, we can use createXXX function for the selector. Have a look at '2nd option' again. What if we use it as a function? That will be our first selector.
export const selectMessage = (state: { message: string }) => state.message;
Then we can use this as;
store.select(selectMessage)
Fun thing about this is, we can re-use one selector to create another using createSelector.
export const selectUppercaseMessage = createSelector(selectMessage, (message: string) => message.toUpperCase());
Sure that example is silly ;) but it does what we want. We use our selectMessage to select the message and do another operation. This can be any operaton, for example a filter. Now anyone who wants the uppercase can directly use this.
store.select(selectUppercaseMessage)
Hence, our selectors (ngrx-hello-selector/src/app/app.reducer.ts)
import { Action, createReducer, createSelector } from '@ngrx/store';

const initialState = 'Hello world';

const _messageReducer = createReducer(
  initialState
);

export function messageReducer(state: string = initialState, action: Action) {
  return _messageReducer(state, action);
}

export const selectMessage = (state: { message: string }) => state.message;

export const selectUpperCaseMessage = createSelector(selectMessage, (message: string) => message.toUpperCase());
Component
export class AppComponent {

  fromKey$: Observable<string>;
  fromMapFn$: Observable<string>;
  fromSelecctor$: Observable<string>;
  fromUppercaseSelector$: Observable<string>;
  
  constructor(private store: Store<{ message: string }>) {
    this.fromKey$ = store.select('message');
    this.fromMapFn$ = store.select((state) => state.message);
    this.fromSelecctor$ = store.select(selectMessage);
    this.fromUppercaseSelector$ = store.select(selectUpperCaseMessage);
  }
}
Now, that's it. Play around this simple example to get a better understanding. Next, we will put everything together we learnt so far in another simple example.

Happy coding ;)