# Angular 的狀態管理 — 使用 Observable Data Service > 利用 RxJS 的 BehaviorSubject,將原本儲存在各 Component 中的狀態,集中儲存在 Service 中,以方便各階層的元件透過 DI 存取,而不需要透過元件間的互動來傳遞狀態數值。 ## 顯示元件單純化 狀態集中管理 以一個簡單的元件互動來做範例  InputComponent 包含一個 input 輸入框,而 ShowComponent 僅是一個灰底的區塊,職責是顯示 input 輸入的數值。而兩個元件並不在元件內部儲存變數值,而是透過 StateService 存取共用的狀態值。這兩個元件程式碼分別如下: **InputComponent** ```javascript= // InputComponent 的 HTML <input #input placeholder="請輸入文字" (input)="change(input.value)" /> // InputComponent Class export class InputComponent implements OnInit { constructor(private stateService: StateService) { } ngOnInit() { } // 當 input 改變時,通知 stateService change(value) { this.stateService.change(value); } } ``` **ShowComponent** ```javascript= // ShowComponent 的 HTML // 用 async pipe subscribe observable <div>{{value$ | async}}</div> // ShowComponent Class export class ShowComponent implements OnInit { // 利用 BehaviorSubject 儲存資料,所以需要使用 Observable type value$: Observable<string> = this.stateService.value$; constructor(private stateService: StateService) { } ngOnInit() { } } ``` ## 使用 BehaviorSubject 的狀態儲存器 StateService 利用 BehaviorSubject 來儲存狀態。 先來談談 Subject。Subject 可以接受 Observer 的訂閱,也可以用來訂閱其他的 Observable,所以他本身既是 Observable 又是 Observer。在他收到所訂閱的 Observable 發出的通知時,會同時通知所有訂閱他的 Observer。 所以 Subject 等同是讓多個 Observer 可以訂閱同一個 Observable 實例,在 Subject 所訂閱的這個 Observable 發出值時,每個訂閱這個 Subject 的 Observer 都收到通知。 BehaviorSubject 繼承自 Subject,因此當然也具有同樣的功能,然而兩者最主要的差異,在於: 1. BehaviorSubject 可以接受給定初值,而 Subject 不可以。 2. Subject 只會在被訂閱之後,而所訂閱的 Observable 有發出新值時,才會做通知。而 BehaviorSubject 會在每一 Observer 訂閱時,對其發出目前已收到的最新值。 也因此 BehaviorSubject 這種類似『狀態暫存』的模式,很適合用來做狀態管理之用。 **StateService** ```htmlmixed= @Injectable({ providedIn: 'root' }) export class StateService { private store$: BehaviorSubject<string> = new BehaviorSubject<string>(''); readonly value$: Observable<string> = this.store$.asObservable(); constructor() { } change(value: string): void { this.store$.next(value); } } ``` - 我們使用 `store$: BehaviorSubject<string>` 做為狀態儲存,並且給定初值為空字串。 - 為了避免讓其他元件直接操作 `store$`,可能會有權限太大的問題(例如 BehaviorSubject 可以調用 next(),而 Observable 不行),利用 `asObservable()` 將 BehaviosSubject 轉換成單純的Observable 再賦值給 `value$`,而 `value$` 是實際供外部取用的變數。 - 提供 `change()` 讓外部元件呼叫,用以更新 `store$` 中的數值。 如此,在每次 InputComponent 中的 input 改變時,便會向 StateService 發出通知,並將新的值塞進 store$ 中,而 store$ 也會透過 value$ 立即通知每個訂閱的 observer。 ## 不同階層元件都可以同時收到新狀態值 如果我們新增一個元件 CounterComponent,要取用並顯示 InputComponent 中輸入字串的長度時,我們同樣也只需要在元件內設定: ```htmlmixed= value$: Observable<string> = this.stateService.value$; ``` 並在模板內使用 async pipe 訂閱,例: ```htmlmixed= <div>{{ (value$ | async).length }}</div> ``` 在每次 store$ 內的狀態發生改變時,CounterComponent 也會同時收到通知  透過 Observable Data Service 集中管理狀態,無論元件是否間隔了很多階層,都可以更簡便地存取狀態值! [本範例 source code](https://github.com/kristxeng/Angular-Observable-Data-Service-Demo)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.