Blog address: 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 are part of the reducer and part of the effect. NgRx ensures that operations are processed by the reducer first, after which they will eventually be intercepted by the effect.
The Reducer processes the action and is then parsed by the effect.
Providing the effects
The input parameters received by forRoot and forFeature are the classes exported by other .ts files, rather than specific class instances. Obtain metadata according to class.
EffectsModule.forRoot can only be called once, because this method will also instantiate other important services of Ngrx, such as EffectsRunner and EffectSources.
The example in Spartacus does not use the forRoot method.
The effects input parameter is an array:
These are the specific effect implementation classes:
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 is equivalent to the model layer, and Store is just the middleware between the consumer and State.
State is where the application stores data.
- the Store entity - the middleman between the data consumer(e.g: a smart component) and the model(the State entity)
Store is a data consumer, such as the middle layer between Angular Component and model (state entity).
effects will be merged.
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 will be merged into an Observable, and the value of the latter's emit is actions.
Store is also an Observer of stream:
effect ---->actions
|- 被 store intercept
actions$
The meaning of AC is a type: extends ActionCreator<string, Creator>
V = Action, if V is not specified, the default type is 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.
After store dispatch, the state machine is migrated first, and the application state changes. This series is driven by the reducer. Then push the action to the 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(eg: 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's filter effect.
OfType
In order to determine which actions should trigger which effects, the OfType custom operator is used.
Maintain the mapping relationship between action and effect.
OfType also uses the filter Operator of RxJS internally:
Take a look at the implementation of 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: Receives two type parameters, T represents the type of the original Observable package, and A represents the type contained in the returned new Observable.
Finally, a new Observable of type B is returned.
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
It can be understood as instructions and dispatched through UI / Service / Effects.
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.
The interface definition of reducer:
export interface ActionReducer<T, V extends Action = Action> {
(state: T | undefined, action: V): T;
}
The above grammar defines an interface, which describes a function type. The curly brackets are the specific definition of the function type. The parentheses are the input interface definition of this function. The function receives two input parameters. The formal parameters are state and action. The types are T (can also accept undefined) and V. The colon after the parentheses defines that the return parameter type should also be T.
Obviously, this function is a state machine that returns a new state based on the current state and the input action (which can be understood as an instruction, an instruction that triggers a state transition).
The way of describing the function signature by defining an interface in TypeScript is very different from the interface in ABAP.
Take the reducer in address-verification.reducer.ts as an example: How is the reducer set up?
In index.ts, use import * as to distinguish these reducers with the same name:
Unified return through getReducers:
Provide provider information through reducerToken and getReducers:
Provider is used in the metadata provided by @NgModule:
Store
It does not store data, it is just a middleware.
Source code:
export class Store<T> extends Observable<T> implements Observer<Action> {
constructor(
state$: StateObservable,
private actionsObserver: ActionsSubject,
private reducerManager: ReducerManager
) {
super();
this.source = state$;
}
/* ... */
}
Store receives data from the outside world, namely 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
| |
-------------
More original articles by Jerry, all in: "Wang Zixi":
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。