Hi welcome back. In this video I'm going to
share with you my personal rating of the top 6 mistakes that developers do in RxJS code. This
video is focused more for beginners with Angular, but I think even more experienced developers can
learn something new from it. If it is your first time on my channel, my name is Dmytro Mezhenskyi and my goal is
to help you to become Advanced Angular developer. Who develops Angular applications consciously knowing
what you're doing and why. In the past I created quite a lot of advanced and unique tutorials
about Angular of course and you can check them out later but now let's focus on RxJS and the
mistakes that we, time after time, see in our code base. All right for this tutorial I prepared a
demo component the code of which is actually full of bad practices and mistakes, but before we start
to explore and fix them all let me very quickly introduce an application and provide more context
about its implementation. So the application mostly consists of one single component the user search
component which allows me to find users by typing their names eventually the users I find will be
displayed there below. We can also define how many results I want to see per page and I can do that by selecting the corresponding value from the dropdown. Okay what about the implementation
the implementation is indeed very simple in the template I have a small reactive form that
contains the text input and the select element and the value of this form is going to be the search
configuration that will be used to configure the HTTP call in the code it looks like the following
you can see that I created an observable searchConfig starting from the form value changes so
when the user changes any of these form controls the new config object is emitted. Then I subscribe
to the searchConfig observable in order to get config object and provide this object to the
findUsers() method as an argument which performs under the hood the HTTP call to the server with
the parameters defined in the searchConfig then I subscribe to the observable that this method
returns in order to kick off the HTTP call once data is received I get it inside the subscribe
callback and assign it to the class property so that I can use this data in the component template
to display their corresponding information. So this is how it is currently implemented, implemented
terribly implemented wrongly, but this is what I see very often reviewing the projects of my
clients now let's see what is wrong with this code . And the mistake number one is nested subscriptions
you know when it comes to the software development I'm a kind of person who tries to avoid such a
strong words like never or always, but this is one of those rare cases where I can undoubtedly say
please never do this. Despite it looking ugly and messy by subscribing to the high order observable
you lose their reactive context for a while, then you probably perform some imperative logic in
between and again you enter the reactive context in the nested observable and this opens a lot of
space for different kinds of mistakes and errors and this is not how you are supposed to work with RxJs. In RxJs you should try to keep your data within the reactive context as long as possible
and resolve data at the very last moment. So how could we make this part better, in scenarios like
this you should always use the RxJs flattening operators. The most popular one is the switchMap() operator which you can apply in the pipe() method of the high order observable. This operator
requires a callback function the argument of which one has a value emitted by the high order
observable. The return value of the callback has to be en nested observable which is in my
case the one that defined users method returns. The switchMap() will under the hood, subscribe
to this nested observable kicking off the HTTP call. And the data returned from the server
will go to the subscribe callback of the high order observable. So now I just have to
clean up my code a little right here and I will get the same result actually as I had
before, but now it is cleaner, it is safer and more predictable, and another cool thing that the
switchMap() operator does is that if a new search config arrives while the current HTTP call is
pending, the switchMap() will cancel the pending call and schedule the new one with the new search
configuration and if you want to learn more about flattening operators in RxJS, and how they
differ from each other I have a series of videos where I cover exactly those operators and you
can check this video out following the hint that should appear right there above. But now let's move
forward to another mistake and the mistake number two, it's a wrong usage of the takeUntil() or takeUntilDestroyed() operators for unsubscription management. Using these operators can give you a
false sense of confidence that you successfully prevented memory leaks, for example in my case
everything looks safe, because I use the takeUntilDestroyed() operator, which is supposed to handle on
subscription when the component is destroyed, right? However approaches based on the takeUntil()
operator they handle on subscription only for the operators located before the takeUntil() and they
have no effect on the downstream subscriptions so if the component is destroyed while the HTTP call
is pending it will not be cancelled which is not necessarily a big issue for a single HTTP call but
if you have a long living subscription something like websocket connection there, then you might
get a problem. So long story short if you choose to handle unsubscription using strategy based on
the take and until operator then make sure that you move this operator to the end of the pipe
operator chain, also you can set up a dedicated Eslint rule in your project to ensure that neither
you or your colleagues will make this mistake in the future. If you want to get more details about
exactly this use case you can check out my another video about exactly this topic again there
will appear the hint and now let's move to the next mistake. And mistake number three it's a
manual subscription in components, but before a short disclaimer I'm not saying that you should
never subscribe manually it is not true true uh sometimes we cannot avoid manual subscriptions
for example, in directives or in services. My point is that in components we have much better options
to deliver data from observables to the component view. For example in my case I could simply
remove the manual subscription like that and the observable itself I can assign to some property
in the component and from here I have already two options if you use signals in your application you
could convert the observable to a signal using the toSignal() helper function, and I would say that in
the modern Angular, it would be a preferable way to do but if you use the older angular version or if
for whatever reason you don't use signals in your app you can always use the good old async pipe for
that you just have to import the async pipe in the component Imports array, and then whenever you
need in a template, you can apply the async pipe to the observable you actually need. In my case
it is users observable, so I can do it just like that. the cool thing about any of these two
approaches is that besides automatic subscription to the observable, they also perform automatic
unsubscription when the corresponding view is destroyed. This means that I can simplify my users
observable even more by removing that takeUntilDestroyed() operator along with the destroy ref
token by the way if you are curious what is destroyRef token and why it exists in Angular
again I have a dedicated video about that you can check this out and yes in this tutorial there will
be quite a lot of references to my other videos but nevertheless let's move forward and talk about
another mistake that we recently introduced during this last refactoring. And mistake number four
it's executing observable logic more times than we need, terrible title, but I couldn't come
up with anything better, in short the problem is the following if I change the search config I
always see two identical HTTP calls in the console. This is something new because we didn't have
this be behavior before and the trick here is that actually, each new subscription to the observable
triggers the execution of the whole operator pipe chain and the creation of the value producer
for each subscriber. For this kind of behavior we have a special term 'Cold observable' and this
is exactly my case as you remember I applied two times the async pipe to the users observable so I
created two subscriptions, two subscriptions means that two times will be executed the observable
logic, which leads to two HTTP calls, simple and again there are a couple of ways how to fix it.
First approach is the wrapping the code with the 'if' block subscribe to the observable there
only once, and then assign the result from this observable to the template variable that you can
use within this blog. Alternatively you can use special operators that make your observable
hot making them share the latest observable value with new subscribers. You can achieve that
using a group of operators like share() or shareReplay() and others, but in my opinion shareReplay() is the most popular and universal one, and the idea here is to define how many value
emissions from the RxJs stream have to be replied to new subscribers. Since I need only latest value
from the observable I define one, as an argument so now when the new subscriber arrives the logic
before shareReplay() will not be executed. Instead shareReplay() will just return the latest value that
was emitted to the stream. So now if we say this change and try to find any other user once again,
you can see that now I don't have duplicated HTTP call which is exactly what I expected, but let's
move forward to mistake number five. And mistake number five it is improper usage of the distinctUntilChanged() operator. To demonstrate this issue I would like to expand the searchConfig$ observable
and let me very quickly break it down. Here you can see the usage of the debounceTime() operator with
the value of 300 milliseconds. I needed to filter out rapid successive emissions to the stream
allowing only the final value to be emitted after the specified 300 milliseconds delay. In such a
way I can reduce the number of HTTP calls and the server load. However it means that the user
can change the searchConfig and revert it back within 300 milliseconds emitting the same config
again and it will cause the same HTTP call. This is exactly what the distinctUntilChanged() operator should prevent, but as you can see it doesn't do its job. The thing is that in this configuration
the distinctUntilChanged() operator works properly only with primitive data like strings,
boolean, numbers, etc. But here the stream emits objects, and to compare if the object has changed
it uses strict comparison, however if you compare two objects like this, you will always get
false, although the shape of the object is the same, that's why if you emit non-primitive data
types in your observable and you use the distinctUntilChanged() operator there you have to use a
predicate function that allows you to compare previous and current values more accurately by
comparing values of certain object keys or make the deep object comparison. And by the way
Pro Tip if you need to track only one object key you can shorten this notation by using another
operator called distinctUntilKeyChanged() and then you just provide as a value the name of
the key you want to track so now let's save our changes and try to reproduce their previous
behavior again. And you can see that this time the HTTP call with the same search config has not been
performed which is actually cool as you can see knowledge about fundamental data structures and
their differences is quite important in software development and if you would like to learn more
about data structures algorithms and computer science, check out platform called brilliant which
is sponsor of today's video what is special about brilliant is that there you can find thousands
of interactive lessons and courses in computer science, data analysis, programming and of course AI
so there you can learn not only computer science and math fundamentals but also algorithmic
thinking and new programming languages like for example python, learning on brilliant is really
easy and engaging because of the Hands-On approach which helps you deeply understand Concepts to try
everything brilliant has to offer for free for a full 30 days check the video description where you
can find a special link brilliant.org/decodedfrontend click on it and you will also get 20% off
for the annual premium subscription and now let's get back to the video. And the last mistake, mistake
number six it is a per forming side effects in the wrong place. In short, side effect is when a
function interacts and modifies anything outside of its scope. This might make your code potentially
harder to understand harder to test and harder to debug. Despite that, we cannot avoid side effects
completely because it is simply impossible for example here in the map() operator besides reshaping
the config object I save also the config in the localStorage this is a side effect, but I cannot
avoid it because it is part of my functionality. The problem here is not the side effect itself,
but more the fact that looking at the code of this observable I have no idea if it performs
side effect or not, and if yes then what exactly will be effective, which component properties
will be modified and so on. That's why in RxJS operators you have to use pure functions means
the functions that don't perform side effects, and if you need to perform them you have to do
it inside the special operator called tap(). This is exactly what this operator is designed for so
in my case, the interaction with the localStorage has to happen right there. So now I can immediately
see that the observable has side effects and I can go and see what exactly happens there which makes
my code more clear and predictable. All right guys thanks for watching, I hope this video was useful
and it will help you to improve the code quality in your angular projects. What would be your
personal rating or the top let's say five mistakes that you see people do in RxJS code, it
would be be very interesting, please share this in the comment section under this video. Otherwise if
you would like to support my channel please share this video with your colleagues and friends,
in your social media profiles, and check out my Advanced Angular video courses they can really
help you to bring your angular skills to a next level. Otherwise guys I wish you productive week
ahead stay safe, and see you in the next video.