Reading your Application State using Selectors
To read your application state in Redux, we need to use the select()
method on @ngrx's Store
class. This method creates andreturns an Observable
that is bound to a specific property in your application state.
For example, here's how you would select the counter
object:
store.select('counter'); // Returns Observable<Counter>
And to fetch the counter's currentValue
, we can pass in a string
array, where each string plucks a single property from the application state one at a time in the order specified:
store.select(['counter', 'currentValue']); // Returns Observable<number>
While select()
allows for several variations of strings to be passed in, it has it's shortcomings - namely you won't actually know if the plucking is working properly until you execute your code.
Because of that, select()
allows you to select values using functions too, which makes things more type-safe and your selectors will be more refactorable by your IDE.
store.select(appState => appState.counter.currentValue);
Creating a Counter Service
While you could inject Store
and select values directly in your Angular components, it's considered to be a best practice to wrap this functionality into separate services. This approach encapsulates all of the selection logic and eliminates any duplication where the selection path is repeated throughout your application.
Let's tie everything together by building out a CounterService
example:
app/services/counter.service.ts
import {Injectable} from '@angular/core';
import {Store} from '@ngrx/store';
import {Observable} from 'rxjs/Observable';
import {AppState} from '../models';
@Injectable()
export class CounterService {
constructor(private store: Store<AppState>) {}
getCurrentValue(): Observable<number> {
return this.store.select(appState => appState.counter.currentValue)
.filter(Boolean);
}
}
Because select()
returns an Observable
, the getCurrentValue()
method also applies a filter()
to ensure that subscribers do not receive any falsy values. This greatly simplifies the code and templates in your components, sincethey don't have to repeatedly consider the falsy case everywhere the value is used.