我正在研究一个相对简单的应用程序,在这里我想了解更多关于NGRX、ReDux和角2的知识。
我将简要介绍我的应用程序的设置、我的应用程序状态和还原程序。
在我的应用程序中,我想用webgl框架在屏幕上绘制某些对象(网格)。我想通过ngrx商店添加一个网格,创建具有这些网格属性的简单对象,并将其保存在app状态。每当添加“mesh”时,我想使用ngrx sideeffects,使用可以访问webgl框架的服务在屏幕上绘制网格。
我的(简化)appstate如下所示:
export interface AppState {
meshList: MeshListReducer.MeshListState
}
要添加网格,我创建了以下减速机函数:
case MeshActions.ADD_MESH: {
return Object.assign({
entities: [meshAction.payload, ...state.entities]
});
}
case MeshActions.ADD_MESH_SUCCESS:
case MeshActions.UPDATE_MESH: {
// This reducer function is only being called once, see below for further explanation.
return Object.assign({}, state, {
entities: state.entities.map(meshItem => {
// If we can find a mesh with this id, use the sub reducer to update it.
if (meshItem.uuid === meshAction.payload.uuid)
return meshSubReducer(meshItem, meshAction);
return meshItem;
})
});
}
default: {
return state;
}
}
export function meshSubReducer(mesh: BaseMesh, meshAction: MeshAction): BaseMesh {
switch (meshAction.type) {
case MeshActions.ADD_MESH_SUCCESS:
case MeshActions.UPDATE_MESH:
return Object.assign({}, meshAction.payload);
default:
return mesh;
}
}
最后是我的effects类,它包含对webgl框架服务的调用,并调用success操作:
@Effect()
addMesh$ = this.actions$
.ofType(MeshActions.ADD_MESH)
.map((action: MeshAction) => action.payload)
.switchMap((payload: BaseMesh) => this._worldService.addMeshToWorld(payload))
.map(payload => this._meshActions.addMeshSuccess(payload));
以及worldservice.addmeshtoworld函数:
public addMeshToWorld(mesh: BaseMesh): Promise<BaseMesh> {
let p = new Promise<BaseMesh>((resolve, reject) => {
let renderer = this._meshRendererFactory.createMeshRenderer(mesh);
// Every call to the ngrx effects always enters this function, and the component is sucessfully added to the canvas.
renderer.addTo(this._world.app).then((component: WHS.Component) => {
resolve(Object.assign({}, mesh, {
rendererId: (<any>component).native.id
}));
});
});
return p;
}
我使用这些分派方法调用所有这些函数:
let soccerBall = new SphereMesh({
geometry: {
heightSegments: 20,
widthSegments: 20,
radius: 5
},
gameMeshType: Enums.GameMeshType.Sphere,
uuid: this._meshHelper.generateUUID(),
meshMaterial: {
color: 0xF2F2F2
}
});
let soccerBall2 = new SphereMesh({
geometry: {
heightSegments: 20,
widthSegments: 20,
radius: 5
},
gameMeshType: Enums.GameMeshType.Sphere,
uuid: this._meshHelper.generateUUID(),
meshMaterial: {
color: 0xF2F2F2
}
});
// Dispatching these straight after each other will cause the succes action to only be dispatched once.
this._store.dispatch(this._meshActions.addMesh(soccerBall));
this._store.dispatch(this._meshActions.addMesh(soccerBall2));
我遇到的问题是,在调用“add_mesh”副作用并将网格添加到屏幕后,该效果只调用最后的“map”操作一次,因此add_mesh_success reducer函数仅对一个网格调用,而不是对另一个网格调用,请参见屏幕截图:
奇怪的是,当我在超时添加第二个分派时,成功调用现在突然被正确地调用所有分派的项目:
this._store.dispatch(this._meshActions.addMesh(soccerBall));
setTimeout(() => {
// Now succes action is suddenly being called twice like it should..
this._store.dispatch(this._meshActions.addMesh(soccerBall2));
}, 1500);
是什么导致了这种奇怪的行为?我觉得我的应用程序相当简单,但似乎我遗漏了一些东西。
我使用的软件包版本如下(我选择了我认为最有用的软件包,请在此提及:
"@angular/core": "^5.0.0",
"rxjs": "^5.5.2",
"@ngrx/effects": "^5.2.0",
"@ngrx/store": "^5.0.0",
"typescript": "~2.4.2"
最佳答案
必须小心使用switchMap
内部效果,我的建议是不要使用它直到你对RxJS感到满意。
为什么switchmap是危险的?因为第二次在第一个完成之前发送相同的动作,它禁用第一个启动的链,并立即执行第二个动作链。
为什么concatMap
有效?它将操作排队。第一个完成后,第二个开始。所以行动之间没有竞争。
关于angular - NGRX效果仅在多个调度上触发一次成功操作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49600644/