NGRX效果仅在多次调度时触发成功操作

时间:2018-04-01 17:19:40

标签: angular typescript redux angular5 ngrx

我正在开发一个相对简单的应用程序,我想了解更多有关ngrx,redux和angular 2的信息。

我将简要介绍一下我的app,appstate和reducers的设置。

在我的应用程序中,我想使用webgl框架在屏幕上绘制某些对象(网格)。我想通过创建具有这些网格属性的简单对象,并通过ngrx存储添加网格,并将其保存在应用程序状态中。每当添加'网格'时,我想使用ngrx sideeffects使用可访问webgl框架的服务在屏幕上绘制网格。

我的(简化)appstate看起来像这样:

export interface AppState {
    meshList: MeshListReducer.MeshListState
}

要添加网格,我创建了以下reducer函数:

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;
    }
}

最后我的效果类包含对webgl框架服务的调用,并调用succes动作:

@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_SUCCES reducer函数对于一个网格而不是另一个网格,请参见屏幕截图:

enter image description here

奇怪的是,当我在超时中添加第二个调度时,现在突然为所有调度的项目正确调用成功调用:

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"

1 个答案:

答案 0 :(得分:6)

必须仔细使用switchMap内部效果,我的建议是不要使用它,直到你对RxJS感到满意为止。

为什么switchMap很危险?因为第二次在第一次操作完成之前调度相同的操作时,它会禁用第一次启动的链并立即执行第二个操作链。

为什么concatMap有效?它排队行动。第一个完成后,第二个开始。因此,行动之间没有竞争。