博客地址:https://indepth.dev/posts/120...
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:
- 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.
Effects 会被 merge 成一个 Observable,后者 emit 的value 就是 actions.
Store 也是 stream 的 Observer:
effect ---->actions
|- 被 store intercept
actions$
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.
Store dispatch 之后,首先状态机迁移,应用程序 state 发生变化,这一系列通过 reducer 驱动。然后把 action push 到 action stream 去。
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>;
/* ... */
}
OperatorFunction: 接收两个类型参数,T 代表原始 Observable 包裹的类型,A 表示返回的新的 Observable 包含的类型。
最终返回一个新的 Observable,类型为 B.
Store.dispatch(event)
Action
可以理解成指令,通过 UI / Service / Effects 来 dispatch.
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$.
allows consumer ↔️ state communication
⬆️
|
|
----------- newState -----------
| | <------------------- | |
| | Store.source=$state | |
| | | | <---- storing data
| Store | Action | State |
| | --------------------> | |
| | Store.dispatch() | |
----------- -----------
| ⬆️
Action | | newState
| |
⬇️ |
-------------
| |
| Reducer | <---- state changes
| |
-------------
更多Jerry的原创文章,尽在:"汪子熙":