我正在研究一个相对简单的应用程序,在这里我想了解更多关于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函数仅对一个网格调用,而不是对另一个网格调用,请参见屏幕截图:
angular - NGRX效果仅在多个调度上触发一次成功操作-LMLPHP
奇怪的是,当我在超时添加第二个分派时,成功调用现在突然被正确地调用所有分派的项目:
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/

10-10 00:42
查看更多