Querying a Normalized State with RxJS in Angular
This post assumes that you at least have some working knowledge of ngrx/store and RxJS.
In this article, we are going to learn how we can query normalized state in our redux store.
Let’s say we have a blog and our normalized state look like this:
First let’s create our smart component.
I’m going to abstract the queries
to a dedicated service for three reasons:
- I do not like the idea of injecting the
Store
into my component. The component does not need to know how he gets the data. ( For the same reason that you do not inject theHTTP
service. ) - I want the ability to reuse my
queries
in any other parts of my application. - I want to keep my component clean.
Now let’s create the ArticlesQuery
.
First, we need to create a dedicated selector for every part of the state so that we can compose them later.
Now let’s say we have a place in the app that needs only the articles. (aside
area for example)
The result
and articles
depend on each other ( if we add new article we need to update both the result
and the articles
), so our best choice is to use the zip
operator.
After all observables emit, emit values as an array
We can also use the second parameter — resultSelector
. A function which takes the inputs at the specified index and combines them together.
combineLatest
will also work but I prefer zip
in this case.
update: combineLatest
is a better option.
Now let’s say we need the articles
with their comments
.
Do you see where I’m going with this? We can compose queries
to get the necessary data.
Now let’s say we need the articles
with their comments
and the authors
.
Now let’s add a selectedArticle
key to our state.
If we want to display the selected article we can use the withLatestFrom
operator.
Also provide the last value from another observable
When the selectedArticle
changes our observable emits new value with the latest articles
and our component will re-render.
If we need only the article
without any other data we can do this:
Angular Router
The Router params
are an observable so for example, if we store the selected id in the URL we can query the article like this:
Form Control
The valueChanges
property is an observable, so for example if we need to implement search we can do this like this:
Let’s say you need to get the favorite articles of a user, and this information is stored in a user
reducer.
You don’t need reselect
The select()
method will give you an observable that calls distinctUntilChanged()
internally, meaning they will only fire when the state actually changes. ( it means when there is a new reference ).
Summary
In the end, you have to remember that everything is a stream. You can use various observables/operators to compose data from your state or any other source.
combineLatest
, withLatestFrom
, zip
, concat
, forkJoin
,merge
and more…
🔥 Last but Not Least, Have you Heard of Akita?
Akita is a state management pattern that we’ve developed here in Datorama. It’s been successfully used in a big data production environment for over seven months, and we’re continually adding features to it.
Akita encourages simplicity. It saves you the hassle of creating boilerplate code and offers powerful tools with a moderate learning curve, suitable for both experienced and inexperienced developers alike.
I highly recommend checking it out.
Follow me on Medium or Twitter to read more about Angular, Vue and JS!