Angular 如何捕获两个(或更多)@ngrx/store操作并在组件中保留订阅,直到发生这种情况?

Angular 如何捕获两个(或更多)@ngrx/store操作并在组件中保留订阅,直到发生这种情况?,angular,ngrx,ngrx-effects,ngrx-store,Angular,Ngrx,Ngrx Effects,Ngrx Store,在我的主组件中,我开始初始化我的数据: _store.dispatch(_statusActions.initialize()); 这将触发所有初始化操作: @Effect() loading$ = this.actions$ .ofType(StatusActions.INITIALIZING) .mergeMap(() => Observable.from([ this._characterActions.initCharacters(),

在我的主组件中,我开始初始化我的数据:

_store.dispatch(_statusActions.initialize());
这将触发所有初始化操作:

@Effect()
loading$ = this.actions$
    .ofType(StatusActions.INITIALIZING)
    .mergeMap(() => Observable.from([
        this._characterActions.initCharacters(),
        this._vehicleActions.initVehicles()
    ]))
将数据加载到存储中后,将触发所有存储实体的成功操作

对于车辆:

@Effect()
loadVehicles$ = this.actions$
    .ofType(VehicleActions.INIT_VEHICLES)
    .switchMap(() => this._vehicleService.getVehicles()
        .map((vehicles: Vehicle[]) => this._vehicleActions.initVehiclesSuccess(vehicles))
        .catch(err => Observable.of(this._statusActions.dataLoadingError('vehicles')))
    );
对于角色:

@Effect()
loadVehicles$ = this.actions$
    .ofType(CharacterActions.INIT_CHARACTERS)
    .switchMap(() => this._characterService.getCharacters())
    .map((characters: Character[]) => 
        this._characterActions.initCharactersSucess(characters))
最后,在触发所有*_DATA_SUCCESS操作之后,我希望触发初始化的操作以将就绪标志放入存储中

export const initReducer = (state: boolean = false, action: Action): boolean => {
switch (action.type){
    case StatusActions.INITIALIZING:
        return false;
    case StatusActions.INITIALIZED:
        console.log('App initialized...');
        return true;
    default: 
        return state;
}
我的问题是——如何做到这一点?如何知道何时触发了所有成功操作

UPD

Snksmtx,我跟随你的第一个更快的adwise

很抱歉有额外的问题,但我真的一直在寻找好的方法来做这个 下一步。如何保持此订阅(组件内部),直到触发我的初始化操作(需要使用if(vehicles.length>0)移除此可怕的拐杖):

我试图在subscribe()之前插入skipUntil(),但现在遇到了问题 从另一个组件打开此组件(当所有数据都已加载时)。在这种情况下,无法再触发订阅回调!我无法理解为什么

...
private initDone$ = new Subject<boolean>();
...

this.initialized$.subscribe((init: Init) => {
  if(init.app) 
    this.initDone$.next(true);
})

this.sub = this.vehicles$.skipUntil(this.initDone$).subscribe(vehicles => {
    if(id)
      this.vehicle = vehicles.find(item => item.id === Number(id))     
    else 
      this.vehicle = new Vehicle(vehicles[vehicles.length-1].id+1, '');

    this.viewReady = true;
  });  
}  
。。。
private initDone$=新主题();
...
此.initialized$.subscribe((init:init)=>{
if(init.app)
this.initDone$.next(true);
})
this.sub=this.vehicles$.skipUntil(this.initDone$).subscribe(vehicles=>{
如果(id)
this.vehicle=vehicles.find(item=>item.id==Number(id))
其他的
this.vehicle=新车(车辆[vehicles.length-1].id+1');
this.viewReady=true;
});  
}  
要重现我的问题,只需按下列表中的一辆车。没有开火。然后按F5->now vehicle loading,beacouse回调按设计启动

完整的源代码如下:,
上次运行的版本

我可以想出两种方法来实现这一点(我确信还有其他方法):

1.在减速器中 通过减少
initReducer
中的两个*\u DATA\u SUCCESS操作,让
initReducer
状态为每个必须成功的请求设置标志,以便将就绪标志设置为
true

init.reducer.ts

导出接口初始状态={
characterSuccess:boolean,
车辆成功:布尔值,
就绪:布尔值
}
常量初始状态={
characterSuccess=false,
vehicleSuccess=错误,
就绪=错误
};
export const initReducer(state:InitState=initialState,action:action):InitState{
开关(动作类型){
/* ...
*其他情况,如初始化或初始化错误。。。
*/
case CharacterActions.CHARACTER\u数据\u成功:{
/*将characterSuccess设置为true。
*
*如果VehicleSucces已为true
*这意味着两个请求都已成功完成
*否则ready将保持false,直到第二个请求完成
*/
返回Object.assign({},state{
人物成功:真的
就绪:state.vehiclesucces
});
}
案例VehicleActions.VEHICLE\u数据\u成功:{
/*将VehicleSucces设置为true。
*
*如果characterSuccess已经为true
*这意味着两个请求都已成功完成
*否则ready将保持false,直到第二个请求完成
*/
返回Object.assign({},state{
车辆成功:对,
准备就绪:state.characterSuccess
});
}
违约:
返回状态;
}
}
2.使用选择器 如果创建
initReducer
只是为了跟踪当前是否正在初始化,则可以忽略整个reducer,而使用计算派生状态的选择器。
我喜欢使用库,因为它可以让您创建高效的选择器,只有在发生更改时才会重新计算(=记忆选择器)

首先,将
加载
-和
就绪
-标志添加到车辆和字符减速器的状态形状中。
然后,在减速器级别添加选择器功能。
车辆减速器示例:

车辆.减速器.ts (对字符缩减器重复相同的操作)

导出接口车辆状态{
//车辆ID和实体等。。。
加载:布尔;
就绪:布尔;
}
常量初始状态:车辆状态={
//其他初始值
加载:false,
就绪:错误
}
导出功能减速器(状态=初始状态,操作:操作):车辆状态{
开关(动作类型){
//其他情况。。。
case VehicleActions.INIT_车辆:{
返回Object.assign({},state{
加载:对,
就绪:错误
});
}
案例VehicleActions.VEHICLE\u数据\u成功:{
返回Object.assign({},state{
/*其他还原逻辑,如
*实体:action.payload
*/
加载:false,
准备好了吗
});
}
违约:
返回状态;
}
}
//选择器功能
export const getLoading=(状态:VehicleState)=>state.loading;
export const getReady=(状态:VehicleState)=>state.ready;
接下来,在根减缩器或放置选择器的附加文件中,组合选择器,以获得所需的派生状态:

选择器。ts

从“/root.reducer”导入{MyGlobalAppState};
从“/vehicle.reducer”导入*作为车辆;
从“/character.reducer”导入*作为fromCharacter;
从“重新选择”导入{createSelector};
//车辆状态选择器
export const getVehicleState=(状态:MyGlobalAppState)=>state.vehicle;
//字符状态选择器
导出常量getCharacterState=(状态:MyGlobalAppState)=>state.charact
...
private initDone$ = new Subject<boolean>();
...

this.initialized$.subscribe((init: Init) => {
  if(init.app) 
    this.initDone$.next(true);
})

this.sub = this.vehicles$.skipUntil(this.initDone$).subscribe(vehicles => {
    if(id)
      this.vehicle = vehicles.find(item => item.id === Number(id))     
    else 
      this.vehicle = new Vehicle(vehicles[vehicles.length-1].id+1, '');

    this.viewReady = true;
  });  
}