深入理解 ngrx effect 背后的工作机制
博客地址:https://indepth.dev/posts/1206/understanding-the-magic-behind-ngrx-effects
an action is a constituent of a reducer, as well as of an effect. NgRx ensures that actions are first handled by the reducers, after which they will eventually be intercepted by the effects.
actions 是 reducer 的組成部分,也是 effect 的組成部分。 NgRx 確保操作首先由 reducer 處理,之后它們最終會被 effect 攔截。
Reducer 處理 action,然后被 effect 解析。
Providing the effects
forRoot 和 forFeature 接收的輸入參數是其他 .ts 文件 export 的 class, 而不是具體的 class 實例。根據 class 獲得 metadata.
EffectsModule.forRoot 只能被調用一次,因為這個方法還會實例化其他 Ngrx 重要的服務,比如 EffectsRunner 和 EffectSources.
Spartacus 里的例子, 并沒有使用 forRoot 方法。
effects 輸入參數是一個數組:
這些都是具體的 effect 實現 class:
Once the effects (classes) are registered, in order to set them up, an observable will be created (with the help of EffectSources) and subscribed to (thanks to EffectRunner);
- reducer: the shape of application
- state entity: where the app information is kept, also where the place actions meet reducers, meaning it’s where reducers being invoked, which may cause state changes
State 相當于模型層,而 Store 只是消費者和 State 之間的中間件。
state 是應用程序存儲數據的地方。
- the Store entity - the middleman between the data consumer(e.g: a smart component) and the model(the State entity)
Store 是數據消費者,比如 Angular Component 和 model(就是 state entity) 之間的中間層。
effects 會被 merge.
all the effects(e.g: those created by createEffect for example) will be merged into one single observable whose emitted values will be actions.
Effects 會被 merge 成一個 Observable,后者 emit 的value 就是 actions.
Store 也是 stream 的 Observer:
effect ---->actions|- 被 store interceptactions$
AC 的含義是一個類型:extends ActionCreator<string, Creator>
V = Action,V 如果不指定,默認類型為 Action:
- ScannedActionsSubject: comes from @ngrx/store and it is a Subject(thus, an Observable) that emits whenever actions are dispatched, but only after the state changes have been handled.
So, when an action is dispatched(Store.dispatch()), the State entity will first update the application state depending on that action and the current state with the help of the reducers, then it will push that action into an actions stream, created by ScannedActionsSubject.
Store dispatch 之后,首先狀態機遷移,應用程序 state 發生變化,這一系列通過 reducer 驅動。然后把 action push 到 action stream 去。
By setting the Actions’ source to ScannedActionsSubject, every time we have something like this.actions$.pipe().subscribe(observer) the observer will be part of ScannedActionsSubject’s observers list, meaning that when the subject emits an action(e.g: subject.next(action)), all the registered observers will receive it. This should explain why all the effects will receive the same actions, but, with ofType’s help, these can be filtered out - OfType 的過濾效果。
OfType
In order to determine which actions should trigger which effects, the OfType custom operator is used.
維護 action 和 effect 的映射關系。
OfType 內部也是用的 RxJS 的 filter Operator:
看看 Observable.pipe 的實現:
export class Observable<T> implements Subscribable<T> {/* ... */pipe<A, B>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>): Observable<B>;/* ... */ }where OperatorFunction<T,A> specifies the type of a function that receives an observable as a parameter and returns another observable:
OperatorFunction: 接收兩個類型參數,T 代表原始 Observable 包裹的類型,A 表示返回的新的 Observable 包含的類型。
最終返回一個新的 Observable,類型為 B.
Store.dispatch(event)
It signals that an event that requires state changes is sent from the UI(e.g a smart component).
Store.dispatch() will push the action(event) into an actions stream(which is different from the one that belongs to the effects):
Action
可以理解成指令,通過 UI / Service / Effects 來 dispatch.
Creator<P, R> is simply a function takes up a parameter of type P and returns an object of type R.
reducer
Reducers are pure functions that are responsible for state changes.
reducer 的 interface 定義:
export interface ActionReducer<T, V extends Action = Action> {(state: T | undefined, action: V): T; }上述語法定義了一個 interface,該 interface 描述了一個函數類型,大括號內是函數類型的具體定義,小括號為這個函數的輸入接口定義,該函數接收兩個輸入參數,形參為 state 和 action,類型分別為 T(也可以接受 undefined) 和 V, 小括號后面的冒號,定義了返回參數類型也應該為 T.
很明顯,這個函數就是一個狀態機,基于當前狀態和輸入的 action(可以理解成指令,觸發狀態遷移的指令),返回新的狀態。
TypeScript 里通過定義接口來描述函數 signature 的這種方式,已經和 ABAP 里的 interface 很不一樣了。
以 address-verification.reducer.ts 里的 reducer 為例:該 reducer 如何被 setup?
在 index.ts 里,通過 import * as 來區分這些同名的 reducer:
通過 getReducers 統一返回:
通過 reducerToken 和 getReducers 提供 provider 信息:
Provider 在 @NgModule 提供的元數據里使用:
Store
并不存儲數據,只是一個中間件。
源代碼:
export class Store<T> extends Observable<T> implements Observer<Action> {constructor(state$: StateObservable,private actionsObserver: ActionsSubject,private reducerManager: ReducerManager) {super();this.source = state$;}/* ... */ }Store 從外界接受數據,即 state$.
Every time the source (state$) emits, the Store class will send the value to its subscribers.
allows consumer ?? state communication??|| -----------? newState -----------? | |?<------------------- | |? | |? Store.source=$state | | | | ? | | <---- storing data | Store |? Action | State |? | | -------------------->? | | | |? Store.dispatch() | |? -----------? -----------?| ??Action | | newState| |?? |-------------?| |?| Reducer |?<---- state changes| |?-------------更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的深入理解 ngrx effect 背后的工作机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 万和热水器售后服务电话号码(万方数据知识
- 下一篇: 皇室战争满级后金卡怎么搞(17173皇室