接下來幾篇並不是要實際做一個 ngrx/store, 而是讓我們用 Observable 的觀念來剖析 ngrx/store 內部的運行方式,實際的 ngrx/store 效率會更好,也會更優化,這裡參考的是這篇Comprehensive Introduction to @ngrx/store,我們希望用模擬的方式來理解它的運作,讓它不再神秘。
先回顧一下 Flux 的兩個核心 Dispatcher 跟 Store
圖片來源
我們將 Dispatcher單獨看一下,它的任務是觀察 Action 的資料流,產生 State 的資料流,而這種既是 Observer 又是 Observable 的,我們之前有提過,就是所謂的 Subject
。
模擬程式如下
interface Action {
type: string;
payload?: any
}
// dispatcher
class Dispatcher extends Rx.Subject<Action> {
dispatch(action: Action) {
this.next(action);
}
}
const dispatcher = new Dispatcher();
const subscribe1 = dispatcher.subscribe(v => console.log('sub1 ===> ', v));
const subscribe2 = dispatcher.subscribe(v => console.log('sub2 ===> ', v));
dispatcher.dispatch({type: 'Action1'});
dispatcher.dispatch({type: 'Action2'});
codepen
簡單說明一下
interface Action {
type: string;
payload?: any
}
2.Dispatcher 的 dispatch
其實就是Subject
的next
3.Dispatcher 會在 Store 的內部作業加工後產生新的狀態 State,但這要等到我們加入 Reducer後,我們以後會談到。
Store 基本上也是觀察 Action 資料流,輸出 State 資料流,但 Store 還有一個任務,我們先看下面的例子
interface Action {
type: string;
payload?: any
}
// first store with Subject
class FirstStore extends Rx.Subject<Action>{}
const firstStore = new FirstStore();
const sub1 = firstStore.subscribe(v => console.log('sub1 ===> ', v));
const sub2 = firstStore.subscribe(v => console.log('sub2 ===> ', v));
firstStore.next({ type: 'Action1' });
const sub3 = firstStore.subscribe(v => console.log('sub3 ===> ', v));
// sub3 did not get current state
如果我們跟 Dispatcher 一樣使用 Subject
的話,當sub3
做subscribe
時,並不能取到最後的狀態(State),然而 store 會直接面對外面的客戶(subscribers),所以我們要的是
還好 RxJS提供了另一種Subject
,這種稱為BehaviorSubject
是跟Subject
一樣可以當 Observer 也可以當 Observable, 除此之外它還會保留最後一筆資料,當有新的 subscriber 時,它可以提供, 例子如下
interface Action {
type: string;
payload?: any
}
// use BehaviorSubject
class SecondStore extends Rx.BehaviorSubject<Action> {
constructor(initialState) {
super(initialState);
}
}
const secondStore = new SecondStore('initial State');
const sub4 = secondStore.subscribe(v => console.log('sub4 ===> ', v));
const sub5 = secondStore.subscribe(v => console.log('sub5 ===> ', v));
secondStore.next({ type: 'Action2'});
const sub6 = secondStore.subscribe(v => console.log('sub6 ===> ', v));
// sub6 get state as well
codepen
它的輸出會跟我們預期般,都會有最新的資料,這裡的輸出輸入都還是 Action, 因為要等到將 Store 跟 Dispather 結合之後,我們才會看到之間的轉換,下次我們就來看如何將 Store 跟 Dispatcher 結合,結合後會是整個 ngrx/store 的大架構。
====補充更新====
CodePen中範例 Rx.subject會出現 undefine錯誤
將Rx開頭變更成 rxjs.subject即可觀看範例