Techbursts zijn tech-artikelen van onze developers. Zij zijn experts binnen hun vakgebied en delen graag hun kennis met andere programmeurs. Don’t keep it in the bubble, burst it!
HTTP-STORE WITH ANGULAR & RXJS
More and more applications are starting to use the so called ‘Flux pattern’ or ‘state container’. A few libraries that implement this pattern are:
Redux – For React
Vuex – For Vue
NgRX – For Angular
This pattern can save you a lot of bugs and in some cases even aid in debugging your application. This is because they provide immutable objects and, more importantly, unidirectional data flow when it comes to managing your data. No more “strange” modifications that have an effect on various places throughout your application or complex state management functions. See for example the facebook notification bug. This is one of the most famous examples that illustrates the reason for Redux’s creation. For more information on Redux see this post.
SHOULD YOU ALWAYS USE NGRX WHEN IMPLEMENTING FLUX?
In my experience, the answer is no. This is mostly because a large application usually has a lot of state management to content with and will therefor use a lot of the library’s features, which makes integrating the library worthwhile. A small application will usually have much less state to manage which makes integrating the library much less worth your while. Adding this library to a small or medium sized application will also create a lot of boilerplate code and adds a lot of unneeded complexity. This in turn makes it harder for new developers to start working on the app.
Are there situations where this pattern comes in handy? Yes! But this doesn’t mean you always have to use a full blown library. One of these situations is managing data from the backend and using this data in multiple places. Thanks to libraries such as RxJS we can do this ourselves!
To demonstrate how we can implement Flux in a simpler way we are going to create a small application. This app will receive a list of to-do’s from the backend and will show these to-do’s on multiple places within the application. The tricky part comes when we change one of the to-do’s and all of the places where the to-do is displayed have to be updated accordingly.
Let’s start by creating a new clean Angular application (see the Angular docs for more info on the commands)
CREATING THE BASE STORE
Since we can have more than one http-store in our application (for example, to-do’s & users) we want to create a base store so that we can reuse the functionality. Create a new Angular service with the following contents. I will go through each section of the code seperately to explain the function of the code (the full service can be found on my gitub):
There is only one real requirement on our entities, they must have an ID. This is so that we can keep track of the entities we have and ensures we can edit and remove the intended entity.
What follows is the definition of the entities$ member. This is an RxJS observable. This object is our single source of truth for everyone that decides to listen (subscribe) to our updates. This object holds all of our entities and can only be modified from within the service, making the data flow unidirectional.
The next property is a somewhat strange object, a RxJS BehaviorSubject. This object allows us to provide updates (via .next()) to the entities$ observable. This is private so that we don’t expose the update functionality to the outside world and thus keeping control over the observable. We connect these two properties in the constructor.
The two functions further down are the modifiers of the entities$ observable, the so-called reducers.
Below that is a generic get function that makes a call to the backend and updates the entities$ object with the newly retrieved data.
What else can we add?
We can provide much more functionality within our service, like:
event messages (like ‘successful get request’);
get an item from the cache;
update an item in the cache;
add an item to the cache;
find and item in the cache;
Remove an item from the cache;
A config object with url’s so that we won’t have to feed it an url for every request we make;
and much more.
If we start expanding this service we might even separate the functionality into two different classes, an entity-store, which contains the entities$ object and the reducers and the http-store that extends from the entity-store, which contains all the default calls (get, update, upsert, delete) to the backend.
But for this turorial we’ll keep it to this simple implementation, since it is enough to support our example.
USING THE STORE
Now that we have created our base store, it is time to start using it. Create a second service in the same folder and add the following code:
Since we are using the HttpClient, do not forget to add the HttpClientModule to the imports array of the app.module.ts!
As you can see this service is quite clean and simple. This is because most of the logic we added to the http-store.service.ts is reusable and only needs typing.
FETCHING SOME TO-DO’S
The next step is to actually fetch some data and display it on the screen. Change the src/app/app.component.ts to the following:
Also change the src/app/app.component.html to display the fetched todo’s:
Notice the | async pipe. This pipe tells Angular to handle our async logic such as subscribe, unsubscribe and returning the actual data. If we now run the application (ng serve) and checkout the result at localhost:4200/, we can see a list of 200 to-do’s with a delete button next to each to-do.
If we would press the delete button we can observe the to-do disappearing off of the list. Now this is in and of itself quite nice. But the main power comes from displaying the data in multiple places and updating the data in all of these places. On to the next step!
SHOWING THE DATA IN MULTIPLE PLACES
So we can already fetch some to-do’s, store them, display them and manage them. But the next step is using the data in multiple places. Let’s create a new component and let it display the current amount of to-do’s.
And register this component in the app.module.ts (declarations: [AppComponent, AmountComponent]). Now in order to use this component we need to reference it from our app.component.html:
And that’s it! If we now run the application again (or check the recompiled content if you didn’t stop ng serve) we can see a count of the to-do’s at the top and a list of to-do’s beneath it. If you would now delete one of the to-do’s you can see the amount of to-do’s decreasing in both components, without any extra code or state management!
As you can see, a full blow Flux library is not always necessary. We can easily write a small store implementation ourselves that better fits our needs. As this implementation grows and more use-cases start to emerge the use of one of the bigger Flux libraries can always be considered. But until then this small store implementation keeps the application simple while still getting the job done.
You can find the full source code of this example on my github: ngHttp-store