阻止路由器导航以防万一 failure/error
Preventing router navigation in case of an effect failure/error
我正在迁移以使用 ngrx Effects,但我遇到了以下问题:因为 dispatch
returns void
我不确定如何如果我的 ngrx 效果发生错误(例如来自 this.userAccountService.updateFirstName(...
),则阻止路由器导航。
来自我的组件class:
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']);
}
}
我的效果class:
@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
);
我不确定使用路由器从效果中导航是否是一个好习惯(甚至可能)。
如果我的效果出现错误,有人可以建议一个干净的解决方案来防止路由器导航吗?
您可以选择以下两种方式之一。
使用 Effect,捕捉 SUCCESS 动作然后重定向:
@Effect() someeffect$: Observable<Action> = this.actions$
.ofType(currentUserAccount.ActionTypes.UPDATE_FIRST_NAME_SUCCESS)
.do(action => /* do redirect (action.payload) */);
有订阅:
假设这是你的状态:
{
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...
});
我建议使用 @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']);
要考虑的另一件事是单个效果可以响应多个动作,因此您可以使用 table 的简单 action-type-to-route 映射来执行如下操作:
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]));
无论您选择哪个选项,使用在效果中启动的导航路由操作都会使事情变得更容易测试table。编写效果测试以确保当效果接收到特定操作时,它会发出适当的操作很容易。有关测试效果的更多信息 here。
我正在迁移以使用 ngrx Effects,但我遇到了以下问题:因为 dispatch
returns void
我不确定如何如果我的 ngrx 效果发生错误(例如来自 this.userAccountService.updateFirstName(...
),则阻止路由器导航。
来自我的组件class:
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']);
}
}
我的效果class:
@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
);
我不确定使用路由器从效果中导航是否是一个好习惯(甚至可能)。
如果我的效果出现错误,有人可以建议一个干净的解决方案来防止路由器导航吗?
您可以选择以下两种方式之一。
使用 Effect,捕捉 SUCCESS 动作然后重定向:
@Effect() someeffect$: Observable<Action> = this.actions$ .ofType(currentUserAccount.ActionTypes.UPDATE_FIRST_NAME_SUCCESS) .do(action => /* do redirect (action.payload) */);
有订阅:
假设这是你的状态:
{ 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... });
我建议使用 @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']);
要考虑的另一件事是单个效果可以响应多个动作,因此您可以使用 table 的简单 action-type-to-route 映射来执行如下操作:
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]));
无论您选择哪个选项,使用在效果中启动的导航路由操作都会使事情变得更容易测试table。编写效果测试以确保当效果接收到特定操作时,它会发出适当的操作很容易。有关测试效果的更多信息 here。