NgRx Ducks | How to use selectors
In my previous Articles about NgRx Ducks, I have shown how a Duck-service can be used to easily dispatch actions or handle side-effects. These techniques belong to the write-API the needs to be implemented if you are using Redux. This article focuses on the read-API. You will learn how NgRx Ducks integrates NgRx selectors seamlessly to provide a simple API for consuming components.
🏃♂️ Let’s start.
Update 🥳
Now, NgRx Ducks has its own Docs-Page showcasing all features.
Happy Reading: https://co-it.gitbook.io/ngrx-ducks/
Show me the code
The code discussed in this article is available on ⚡️ StackBlitz. There you will have a deeper look at how the respective code-parts are related to each other.
Pick all the things
To allow reading state from the Store a Duck provides a method called pick that accepts NgRx-selectors. Behind the scenes pick
just uses store.pipe(select(...))
to get the desired information.
Let’s assume you already have a selector in your NgRx project like the following.
const visitCounter = createFeatureSelector<CounterState>('counter');export const currentCount = createSelector(
visitCounter,
c => c.count
);
It just reads the current count from the store and automatically informs when the count changes.
Using pick you can use selectors like this easily.
...
import * as selectors from '../store/counter.selectors';@Component({ ... })
export class CounterComponent {
count$: Observable<number>;constructor(@Inject(CounterDuck) private counter: Duck<Counter>) {
this.count$ = this.counter.pick(selectors.currentCount);
}
}
The method pick
enables you to interact with the store without the need to inject the Store-dependency. You can read data from each slice of the store. If you already use the Store as the one and only API for your component the Duck-Service simply replaces the Store.
Furthermore, the NgRx Ducks library allows you to make selectors part of your Duck-service.
Turn selectors to consumable Observables
Instead of using pick
you also can add a selector to your Duck-service. The NgRx Ducks library implements a convention simplifying the usage of a selector a bit.
import * as selectors from './counter.selectors';@Ducksify<CounterState>({
initialState: {
count: 0,
isLoading: true
}
})
export class Counter {
current$ = selectors.currentCount;// ...
}
The code above shows that selectors.currentCount
is assigned to a property current$
. If you are familiar with the Finnish Notation for observables you already know what this means. The Duck-service will wrap the selector into a call like this: store.pipe(select(selectors.currentCount))
.
For the consuming component, the selector automatically becomes a consumable Observable.
How this works
You may ask how this can be done. How can a selector be turned into something else?
The decorator @Ducksify
does the code transformation. It analyses if a property is a selector. If a selector
is detected it is used within the select
-operator coming from NgRx. This process is called Monkey-Patching.
Since we are in TypeScript-Land it is possible to add type-information to have the nice auto-complete-feature in your IDE. This is one reason why a Duck needs to be injected with the generic Type Duck<T>
. Using this type the structure of the Service gets analysed and if a selector is detected Duck<T>
tells the TypeScript-Compiler that the corresponding property becomes an Observable.
A Duck performs typed monkey patching 🍽 serving the component a simple API.
Benefits
The integration for selectors was added to the Ducks-library because it enables to compose the read- and write-API that is naturally separated using Redux.
A component just needs the Duck-service to discover all possible queries or mutations concerning a certain state slice. This solves one serious problem that bigger NgRx projects have. You do not need to look up multiple files to see what others already have implemented. The risk to reimplement an action or a selector will be reduced by using NgRx Ducks.
Recapitulation
pick
can be used to read data from each state sliceselectors
can be directly integrated into the Duck-serviceselectors
get transformed by @Ducksify to be consumed as Observables- The 🐥 Duck adds higher discoverability to already implemented features.
- The 🐥 Duck composes read- and write-API and provide a dynamically typed facade.
That’s it ✨
Thanks for reading the third article about NgRx Ducks. I hope you enjoyed it. 🤗 If you have any further questions or ideas to improve this project please leave me a comment below.
You also can send me a message on Twitter: @GregOnNet
Since a new article has been published I will tweet about it as well.
Rock On And Code
Gregor
Related Articles
I have written several articles about NgRx Ducks. Basically, it is all about automating the creation of an easy-to-use facade. If you want to know more about Facades itself I recommend to read Thomas Burleson’s article NGRX + Facades.