使用@ngrx / effects调度多个操作,同时确保它们按顺序执行

时间:2017-12-06 10:26:03

标签: angular rxjs5 ngrx ngrx-effects

我很好奇是否有任何方法可以确保在返回多个操作时@ngrx/effects中的操作顺序作为对其他操作的响应。

ActionA => emit ActionB (=> emit async ActionB1, ActionB2) and then ActionC

我希望实现ActionAActionBActionB1ActionB2ActionC的序列。

可以使用concatMap,但似乎无法确保在发出C之前处理动作B1和B2。

真实世界的例子:

@Effect()
oauthLoginAsSomeoneElse$: Observable<Action> = this.actions$
    .ofType<AuthActions.OAuthLoginAsSomeoneElse>(AuthActions.OAUTH_LOGIN_AS_SOMEONE_ELSE)
    .pipe(
        concatMap(action => [
            // First logout
            new AuthActions.OAuthLogout(),
            // Then login again
            new AuthActions.OAuthLogin({redir: action.payload.redir})
        ])
    );

@Effect({dispatch: false})
oauthLogin$: Observable<Action> = this.actions$
    .ofType<AuthActions.OAuthLogin>(AuthActions.OAUTH_LOGIN)
    .pipe(
        map(action => oauthRedir.start(
            this.authEndpoint + '/oauth/authorize',
            this.authClientId,
            this.authRedirectUri,
            this.appBaseHref,
            action.payload.redir,
        ))
    );

@Effect()
oauthLogout$: Observable<Action> = this.actions$
    .ofType<AuthActions.OAuthLogout>(AuthActions.OAUTH_LOGOUT)
    .pipe(
        switchMap(action =>
            this.http.post(`${this.authEndpoint}/logout`, null, {withCredentials: true}).pipe(
                map(responseData => new AuthActions.SessionTerminate()),
                catchError((err: HttpErrorResponse) => {
                    return of(new RouterActions.Go({path: ['/']}));
                }),
            )
        )
    );

您可能希望,在调度OAuthLoginAsSomeoneElse时,与OAuthLogout操作相关的所有内容都将完成(包括@Effect()发出的操作中的一些异步内容),然后再次发出OAuthLogin 。我的意思是,首先处理第一个根动作及其子节点,然后处理下一个发出的根动作。

您知道如何实现这种情况吗?我目前的解决方法是将下一个动作作为参数发送到OAuthLogout,但这并不能很好地扩展,并且很快就会变得非常复杂。

1 个答案:

答案 0 :(得分:0)

有些晚,但仍是最新的。您可以使用效果来确定触发操作的顺序,即使没有附带HTTP请求或其他请求也是如此。这样,您可以轻松设置一系列操作。使用最新的NgRX效果语法,其外观将类似于以下内容:

首先设置一个在actionB之后触发actionA的效果。

effect1$ = createEffect(() => this.actions$.pipe(
  ofType(actionA),
  mapTo(actionB())
));

在执行动作B之后,您可以定义它应该触发actionB1。您还可以传递有效载荷。

effect2$ = createEffect(() => this.actions$.pipe(
  ofType(actionB),
  map(payload => actionB1(payload)
));

当然应该有适当的效果名称,依此类推。但希望您能明白这一点。只需使用ofTypemap指定顺序即可。


以您的真实示例为例,您还需要“响应”操作,例如loginSuccessloginFailedlogoutSuccess等。在适当位置使用这些操作即可以上方法来创建明确定义的动作序列。