Angular - BehaviorSubject ve Change Detection Nedir ? Nasıl Kullanılır ?

Bir login işlemi yapıldığında her component içinde kontrol yapılması çok sağlıklı bir işlem değil. Bir kontrol için kodu defalarca tekrarlamış olacağız ve durum değiştiğinde tepki süresi daha da zorlaşmış olacak.

Bu yüzden Rxjs içinde gayet yetenkli arkadaşlarımız var. Alternatif olarak, Observable ve Subject nesnelerini sayabiliriz. Ama bu iki yapıyı da birleştiren daha yetenekli bir arkadaşımız var; "BehaviorSubject".

Observable ve Subject yapısını birleştiren gayet yetenekli bir yapı olan BehaviorSubject, hem subscribe olunabilen hem de yayın yapabilen bir yapıya sahip.

Böylece tek bir yapı ile, hem componentlerin abone olmasına izin vereceğiz hem de login gibi işlemler için kullanışlı yayınlar yapabileceğiz.

Örnek bir Auth servisi yazalım.

import {Injectable} from '@angular/core';
import {Http} from "@angular/http";
import {BehaviorSubject, Observable} from "rxjs";

class User {
	public username: string;
	public password: string;
	public email: string;
}

@Injectable()
export class AuthService {
  isLoggedIn = new BehaviorSubject<boolean>(false);
  userInformations = new BehaviorSubject<User>(null);

  constructor(private http: Http) {
  }
}

BehaviorSubject oluşturmak için default bir değer ataması yapmak gerekmektedir.

 login(email, password): Observable<boolean> {
    let loginUrl = `http://localhost:3000/auth/login`
    return this.http.post(loginUrl, {email, password})
      .map(_res => _res.json())
      .map(_res =>{
        let message= _res.message;
        if(message.token){
          localStorage.setItem('token',message.token)
          localStorage.setItem('userInfo',message.user)
          this.isLoggedIn.next(true);
          this.userInformations.next(message.user);
          return true
        }
        return false;
      })
  }

BehaviorSubject bahsettiğimiz gibi, hem yayın yapabilen hem de abonelere istediğimiz zaman dataları .next() fonksiyonu ile ulaştırabileceğimiz bir imkan sunmakta.

Son olarak, logOut metodumuzu da eklememiz gerekmekte. Bir kullanıcı çıkış yaptığında tüm uygulamaya yayın yapmalıyız.

logOut() {
	localStorage.removeItem('token');
	localStorage.removeItem('userInfo');
	this.userService.isLoggedIn.next(false);
	this.userService.userInformations.next(null);
}

Şimdi componentlerimizde observable türündeki yayınları nasıl kullanacağımıza bakalım.

 <div class="col-md-12">

    <div *ngIf="(userService.isLoggedIn | async)">
      <button (click)="logout()" class="btn btn-sm danger">Logout</button>
    </div>

    <div *ngIf="userService.userInformation | async as user; else noUser">
      <strong>Hello {{user.name}}</strong>
      <hr>
    </div>

    <ng-template #noUser>
      <strong class="alert alert-warning sm">Please Sign in...</strong>
    </ng-template>
  </div>

Not:

React'ın, view'i tekrar render etmesi için view'in state'inin değişmesi gerekiyor. Bunun ne gibi bir artısı var sorusunun cevabı ise React data'nın değiştiğini anlamak için Angular gibi dirty-checking veya data objectini sürekli dinlemek gibi işlemler yapmak zorunda kalmıyor. Eğer Angular tarafında big data barındıyor ve view kısmında yoğun component kullanıyorsanız, ChangeDetection (yukarıda bahsettiğimiz sürekli dinleme olayı) konusunda büyük bir performans sorunu yaşayacağınızı düşünüyorum. Sürekli değişen bir data olmadığı takdirde ChangeDetection olayını (ChangeDetectionStrategy.OnPush) kapatıp, BehaviorSubject yapısı ile sadece siz datayı güncellediğiniz zaman componenti yeniden render etmesini sağlayabilirsiniz.

Change Detection Strategy türlerine bakalım.

  1. ChangeDetectionStrategy.Default, süppeeer yavaş. Çünkü abone olduğunuz tüm veriler, o anda etkin olan tüm componentlerde sürekli kontrol ediliyor olacaktır.
  2. ChangeDetectionStrategy.OnPush, gayet uygun ve hızlı bir component yapısı. Çünkü, component ağacında, sürekli abone olunan dataları kontrol etmektense, sadece abone olduğunuz datanın change eventi tetiklendiğinde çalışacak bir yapı. (React tarafından aşina olduğunuz this.setState() eventinin karşılığıdır. )

Umarım yardımcı olabilmişimdir.

Herkese kolay gelsin.