RxJS —Two Data Retrieve Patterns for you to use.
Hey Hey foooolks! I hope you all are doing great.
In this article I want to talk about some patterns that we can use with RxJS which will make your code better and less verbose :)
Before we begin, I just want to recommend the reading of my other article if you want to have an overview about the RxJS library:
To exemplify the patterns bellow, I’m going to use a context of an Angular application consuming data from the F1 API.
So, the first pattern that I want to talk about is:
Retrieving data pattern — This is one of the most common operations that we have to deal with in our daily routines. To exemplify this concept, let’s see the classic pattern for retrieving data. We usually have a service like this:
The code above should look very familiar to you. We are simply doing an HTTP request to get some data and using the pipe operator to pipe the tap() and catchError() operators from RxJS in order to display the data or catch any errors that may occur during the request. Now, let’s have a look in the code of our component:
Again, a code that should look very familiar to you. In the component file, we are simply taking the drivers array received from the request and putting it in the component level property so we can bind this in the template file.
Now, what I want to highlight is that the code above is Procedural. What I mean by procedural is that we are using a getDrivers() method in order to retrieve our data. What if we took a declarative approach instead? Let’s compare to see how it would look like.
With the declarative approach, instead of calling a function to get the data, we are simply declaring a variable with the sufix $ (the dollar sign in the end of a variable name is a convention to identify observables) and assigning the return of the HTTP request to this variable. Now we have an observable that holds the result of the operation. Let’s see how the component file would look like with this change:
Ooooh, boy. Instead of 10 lines of code, now we would have just one in our component file. With the declarative approach we don’t need to subscribe and unsubscribe from our observable anymore. Therefore, we don’t need the life cycle hooks onInit and onDestroy either. But will this work? We need to subscribe to an observable in order to it emit a value, right?
Yes, that is correct and we can do that by using the async pipe in the template file.
The async pipe is an angular pipe, do not confuse it with the pipes from RxJS. According to the angular documentation, what the async pipe does is:
It automatically subscribes and unsubscribes to an
Observable
orPromise
and returns the latest value it has emitted.
In our template file, we would have something like this:
So, this syntax async as drivers
means that the async pipe will automatically subscribe and unsubscribe to the drivers$ observable and put the value emitted in the drivers variable that we can now access in our template :)
This is the first pattern that you can use to simplify your code!
The second pattern that I want to talk about is a variation of the first, which is:
Retrieving Data on Action pattern— Again, another pretty common operation that we need to deal with in our routines. So, for this example, let’s imagine that we have a select field filled with seasons from 2018–2022. We want to select a season and based on this user action, show information about the races of this season. Let’s start with our service again.
The first thing that we do is to create a Subject of type string. A Subject is a special type of observable that we can use. We are going to use this Subject to emit the data coming from the UI. Second, we create a public variable that will be our observable. Note the $ sign at the end of the variable name again to indicate that it will be an observable. Then, we’re going to defined a method called selectedSeasonChanged() that will be responsible for emitting the data coming from the UI.
Now, based on the season selected by the user, we need to fire a HTTP request to get the data from races of that particular season. We know that our raceSeasonSelectedAction$ will emit a new season, so now we can pipe this observable to access its data flow.
*Important note here: Notice that now we have an inner observable from the this.http.get
and also the outer observable which is the raceSeasonSelectedAction$
.
So in order to subscribe to an inner observable and flatten the result, we need to use a higher-order mapping operator (flattening operator). These operators automatically subscribe and unsubscribe to inner observables. e.g. switchMap, concatMap and mergeMap.
We’re going to use the switchMap operator because it stops the current operation and performs a new one automatically every time a new data is emitted, which makes him perfect to use with HTTP requests. The code in our service is pretty much done. Let’s have a look in our component code now.
We’re defining a seasons array and initializing it in our constructor with values from 2018–2022. Then, again we are binding the observable from our service to a component variable in order to use it in our template (line 9). Finally, we defined a method called onSeasonSelected() that will be responsible for getting the value selected by the user and sending it to the method in our service which will emit a new data on the stream.
Last, but not least we have our template file.
On lines 1 to 8 we are simply defining a select box which will hold the season values and when the user click on a season, it will call the function onSeasonSelected() that will pass its value to the service to be emitted into the stream.
In conclusion, these were the two patterns that I wanted to share with you all. I have created a little application based on the F1 APIs to study these concepts and you can find the code here and a live preview of the application here.
Also, this article is based on the video from Deborah Kurata which you can watch it here. It really changed my mind regarding how to think about reactive components after I watched her other video here. I strongly recommend you follow her on YouTube :)
I hope you like this article.
Nice coding!!