In this article i will show few techniques that we can use when using Angular + NGRX + FIREBASE to have good performance.

NgRx is great solution for apps with medium complexity. Redux pattern combined with power of RxJs really fits into Angular ecosystem and adding Firebase Realtime Database or Firestore will make your app really fast and reactive. Angular uses Observables intensively, NgRx is built with Observables and AngularFire2 (also changed to @angular/fire) too, so we can do a lot of complex stuff with our data and state. However Observables are not so easy to learn for beginners and many people avoid NgRx due its boilerplate, and even who use them, they do with mistakes that cause performance issues and memory issues.

Mistake 1. Not Unsubscribing (in general)

There are two type of observables, first that emit value and complete, and second that emit values and do not complete automatically. For observables that mostly emit one value and complete i will call finite and for observables that keep emitting values until we manually tell them to stop — infinite . When we subscribe to an observable, we have to unsubscribe from it, otherwise it will cause memory leaks and unexpected behavior in the application.

As i mentioned Angular uses RxJs and observables massively. One of the example is HttpClient provided by Angular. We use HttpClient to make request to the server, and the response is Observable. However the observable returned by HttpClient is finite , so we usually don’t, but can manually unsubscribe from it.

Finite observables emit value and complete automatically , so there will be no issues if you won’t unsubscribe from Http request.

Another thing is infinite observable. When we subscribe to infinite observable we have to unsubscribe from it at some point. If we forget, it will cause memory leaks and unexpected behavior in our app as infinite observables won’t complete automatically. There are many infinite observables in Angular (route events, form changes) and if we don’t unsubscribe we will have problems. We will have even more problems when using NgRx and Firebase.

Everything that NgRx provides are actually infinite observables, and most of firebase query methods also return infinite observables. In this case you need to be careful and unsubscribe from them.

Always think about when to unsubscribe when using NgRx (when selecting state from store) or Firebase

Mistake 2. Using flatMap(mergeMap) instead of switchMap when getting data via Effects from Firebase

When we use NgRx, we should use all powerful features that this state management system provides. One of them is Effects which is used for handling asynchronous operations. For example if we want to load data into our component, we dispatch an action, which will be handled in Effects . Effect will fetch the data and dispatch new action which will update the state.

Consider following effect.

@Effect()

loadPosts$ = this.actions$.pipe(

ofType(LOAD_POSTS),

pluck(‘payload’),

flatMap(uid =>

this.db.getAllPosts(uid).pipe(

tap(() => console.log(‘Data loaded’))

),

map(posts => new LoadPostsSuccess({ entries: posts }))

)

)

);

We listen for LOAD_POSTS action, when that happens we grab the uid of the user and get the data from firebase (which gives infinite observable ). Now consider following scenario. We are in a component A, where this action is dispatched in ngOnInit() , then we navigate to another component B, then come back to A (dispatched again), then B and so on few more times. Now when something changes in our database and because we are subscribed to that changes we will see LoadPostsSuccess action dispatched numerous times (depending on how many times we came back to component A). The reason is because we are using flatMap operator. Each time we open page A (component is initialized), the effect will work and add another subscription to db changes. The easiest way to solve this issue is to use switchMap. This operator will unsubscribe if there are previous subscriptions, so when we navigate to another page and come back, we will have only one active subscription.

If you want to know more about operators like flatMap or switchMap please read this article.

Mistake 3. Not unsubscribing from Firebase in Effects

Although in the example above i showed how to avoid executing the code multiple times when using switchMap, there is still a problem. Because firebase query methods give infinite observables, even when we navigate to another page, we still are listening to changes from our database. Consider example above with switchMap(). We are in a component A, the action LOAD_POSTS is dispatched. After getting data LoadPostsSuccess action is dispatched. Now we navigate to component B. We manipulate the data in our database and because we are still subscribed to those changes, we will see LoadPostsSuccess action dispatched again. When we navigate to component A, we will see LOAD_POSTS and after that LoadPostsSuccess dispatched. So you might ask where is the problem ? The problem is that we don’t need in this particular case to continue listening LOAD_POSTS from database when we are not in component A, because anyway when we navigate to component A, this action ( LOAD_POSTS ) will be dispatched again.

This is not a huge issue, however you might want to unsubscribe from firebase stream when you are not in a component who is responsible for rendering that data from firebase. You might perform transformations with data, or even more complex operations. There is no need to keep listening to that stream, when anyway nothing will be shown in the template.

We can use take(1) to take only first emitted value from firebase and unsubscribe, however in this case we won’t have live changes from firebase. What we actually need is to have live changes from firebase if we are in a component A, and unsubscribe from that stream when we are not in a component A anymore. There is no standard mechanism of doing this, and there are many techniques we can use. The one that i find easy is to use a service which has a Subject.

A Subject is a special hybrid that can act as both an observable and an observer at the same time.

The service is very simple. (subscription.service.ts)

@Injectable({

providedIn: ‘root’

})

export class SubscriptionService {

public unsubscribeComponent$ = new Subject<void>();

public unsubscribe$ = this.unsubscribeComponent$.asObservable();

}

We have two public fields. unsubscribeComponent$ which should be used in the component and unsubscribe$ which should be used in the effect.

Modify effects file with including this service in the constructor and adding takeUntil(this.subService.unsubscribe$) to cancel subscription when navigating away from component.

constructor( private subService: SubscriptionService)

@Effect()

loadPosts$ = this.actions$.pipe(

ofType(LOAD_POSTS),

pluck(‘payload’),

switchMap(uid =>

this.db.getAllPosts(uid).pipe(

takeUntil(this.subService.unsubscribe$)

),

map(posts => new LoadPostsSuccess({ entries: posts }))

)

)

);

Now in the component where we dispatch this action, we need to inject this service and call the next() method of unsubscribeComponent$ Subject in the ngOnDestroy() method.

//A.component.ts constructor( private subService: SubscriptionService) ngOnDestroy(): void {

this.subService.unsubscribeComponent$.next();

}

Now when we are in the component A, we see all live changes from firebase, but when we navigate away we won’t listen to these changes anymore and when we activate component A again the action will dispatched and we will see live changes again.

Thanks for reading full article. There are many many more cool things you can do with Angular+ RxJs + Firebase which will be covered in next articles.