2

我正在迁移以使用ngrx 效果,但我遇到了以下问题:由于dispatch返回void我不确定如果我的 ngrx 效果(例如 from this.userAccountService.updateFirstName(...)发生错误,如何防止路由器导航。

从我的组件类:

  updateFirstName() {
    this.formStatus.submitted = true;
    if (this.formStatus.form.valid) {
      //Dispatch from the store
      this.store.dispatch(new UpdateFirstNameAction(this.formStatus.form.value.firstName));
      //Undesired behavior: will navigate even in case of error/failure!
      this.router.navigate(['/dashboard/useraccount']);
    }
  }

从我的效果类:

  @Effect()
  updateFirstName$: Observable<Action> = this.actions$
    .ofType(currentUserAccount.ActionTypes.UPDATE_FIRST_NAME)
    .map((action: UpdateFirstNameAction) => action.payload)
    .switchMap(firstName =>
      this.userAccountService
        .updateFirstName(firstName)
        .map(() => new UpdateFirstNameSuccessAction(firstName))
        //I obviously can't navigate from here
    );

我不确定使用路由器从效果中导航是否是一种好习惯(甚至可能)。

如果我的效果发生错误,有人可以建议一个干净的解决方案来防止路由器导航吗?

4

2 回答 2

2

我建议使用该@ngrx/router-store模块。有了它,您可以创建路由操作,并且使用它,您有几个选择。

您可以从单个效果发出多个动作。所以你的效果可以concatMap用来发出两个动作:你的成功动作和路由动作(使用go动作创建者创建):

import { go } from '@ngrx/router-store';
import 'rxjs/add/operator/concatMap';

@Effect()
updateFirstName$: Observable<Action> = this.actions$
  .ofType(currentUserAccount.ActionTypes.UPDATE_FIRST_NAME)
  .map((action: UpdateFirstNameAction) => action.payload)
  .switchMap(firstName => this.userAccountService
    .updateFirstName(firstName)
    .concatMap(() => [
      new UpdateFirstNameSuccessAction(firstName),
      go(['/dashboard/useraccount'])
    ])
  );

但是,您可能还需要考虑使用仅管理路由的单独效果:

import { go } from '@ngrx/router-store';
import 'rxjs/add/operator/mapTo';

@Effect()
updateFirstRouting$: Observable<Action> = this.actions$
  .ofType(currentUserAccount.ActionTypes.UPDATE_FIRST_NAME_SUCCESS)
  .mapTo(go(['/dashboard/useraccount']);

要考虑的另一件事是单个效果可以响应多个动作,因此您可以使用简单的动作类型到路由映射表来执行以下操作:

import { go } from '@ngrx/router-store';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';

simpleRoutes: { [type: string]: string } = {
  [currentUserAccount.ActionTypes.UPDATE_FIRST_NAME_SUCCESS]: '/dashboard/useraccount'
};

@Effect()
simpleRouting$: Observable<Action> = this.actions$
  .map((action) => this.simpleRoutes[action.type])
  .filter(Boolean)
  .map((route) => go([route]));

无论您选择哪个选项,使用在效果内启动的导航路由操作都可以使事情更容易测试。编写效果测试很容易,以确保当效果接收到特定动作时,它会发出适当的动作。这里有更多关于测试效果的信息。

于 2017-02-13T06:40:33.450 回答
0

您可以通过以下两种方式之一进行操作。

  1. 使用 Effect,捕获 SUCCESS 动作,然后重定向:

    @Effect() someeffect$: Observable<Action> = this.actions$
        .ofType(currentUserAccount.ActionTypes.UPDATE_FIRST_NAME_SUCCESS)                
        .do(action => /* do redirect (action.payload) */);
    
  2. 订阅:

    假设这是您的状态:

    {
        account: {
            username: null
        }
    }
    

    零件:

    var username$ = this.store.select(account => account.username);
    
    username$.subscribe(user => {
        // the user have changed due to reducer who is getting the action with new user.
        // do here redirect...
    });
    
于 2017-02-12T16:37:44.503 回答