深入理解 ngrx effect 背后的工作机制

简介: 深入理解 ngrx effect 背后的工作机制

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.image.png


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 方法。


image.png


effects 输入参数是一个数组:



image.png

这些都是具体的 effect 实现 class:

image.png


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:


image.png


effect ---->actions

               |- 被 store intercept

1

2

actions$



AC 的含义是一个类型:extends ActionCreator




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 implements Subscribable {

 /* ... */

 

 pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;

 

 /* ... */

}

1

2

3

4

5

6

7

where OperatorFunction 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 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 {

 (state: T | undefined, action: V): T;

}

1

2

3

上述语法定义了一个 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 extends Observable implements Observer {

 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


allows consumer ↔️ state communication
        ⬆️
        |
        |
-----------      newState          -----------                         
|         | <-------------------   |         |                         
|         |  Store.source=$state   |         |
|         |                        |         | <---- storing data 
|  Store  |      Action            |  State  |                         
|         | -------------------->  |         |
|         |   Store.dispatch()     |         |          
-----------                        ----------- 
                                   |        ⬆️
                          Action   |        | newState
                                   |        |
                                   ⬇️        |
                                  ------------- 
                                  |           | 
                                  |  Reducer  | <---- state changes
                                  |           | 
                                  -------------
相关文章
|
3月前
|
应用服务中间件
执行 ABAP 代码出现超时的原因,背后的理论和解决方案
:执行 ABAP 代码出现超时的原因,背后的理论和解决方案
17 0
|
7月前
|
缓存 前端开发 JavaScript
React-Query:解锁你的应用程序潜力,轻松解决接口请求难题!
许多状态管理库,比如`redux`,可以很流畅的管理页面的状态,也有处理副作用的能力,但往往不能很好的处理服务端的状态。
65 1
React-Query:解锁你的应用程序潜力,轻松解决接口请求难题!
|
9月前
|
Go 调度
Go并发调度-调度器设计理念从何而来?为何如此高效?
Go并发调度-调度器设计理念从何而来?为何如此高效?
|
10月前
|
数据可视化 数据库
deconstructSigs|探寻cosmic的独特“气质”-mutation signature !
deconstructSigs|探寻cosmic的独特“气质”-mutation signature !
EMQ
|
SQL 传感器 JSON
eKuiper Newsletter 2022-07|v1.6.0:Flow 编排 + 更好用的 SQL,轻松表达业务逻辑
eKuiper本年度第二个大版本 v1.6.0正式发布,面向Flow编排的图规则API已开发完成,同时达成了多个SQL语法和函数的提升,期望覆盖更多样的使用场景,帮助用户进一步减少定制开发的需求和成本。
EMQ
265 0
eKuiper Newsletter 2022-07|v1.6.0:Flow 编排 + 更好用的 SQL,轻松表达业务逻辑
|
机器学习/深度学习 缓存 前端开发
基于 Observable 构建前端防腐策略
To B 业务的生命周期与迭代通常会持续多年,随着产品的迭代与演进,以接口调用为核心的前后端关系会变得非常复杂。在多年迭代后,接口的任何一处修改都可能给产品带来难以预计的问题。在这种情况下,构建更稳健的前端应用,保证前端在长期迭代下的稳健与可拓展性就变得非常重要。本文将重点介绍如何利用接口防腐策略避免或减少接口变更对前端的影响。
基于 Observable 构建前端防腐策略
|
存储 中间件
深入理解 ngrx effect 背后的工作机制
深入理解 ngrx effect 背后的工作机制
深入理解 ngrx effect 背后的工作机制
SAP Spartacus cxFocus Directive施加后导致tabindex为-1的副作用研究
SAP Spartacus cxFocus Directive施加后导致tabindex为-1的副作用研究
SAP Spartacus cxFocus Directive施加后导致tabindex为-1的副作用研究
|
缓存 移动开发 前端开发
从 SWR 开始 — 一窥现代请求 hooks 设计模型
本文将以 swr 为例子,讲述现在最热门的 useRequest、swr 和 react-query 三个请求 hooks 的新机制,以及新机制后 class Component 和 hooks 在设计上的区别。
从 SWR 开始 — 一窥现代请求 hooks 设计模型
|
SQL 监控 Kubernetes
10个特性:这才是你需要的Trace方案
分布式链路追踪(Distributed Tracing,简称Trace)又名全链路数据追踪,为业务系统提供了整个服务调用链路的调用关系、延迟、结果等信息。本文主要介绍Trace方案的一些高级特性,让大家可以更好的使用Trace来解决业务可观察性的问题。
4938 2
10个特性:这才是你需要的Trace方案