Ngrx 导致挂起问题,直到订阅 store.dispatch 时重新加载页面
Ngrx causes hanging issue until page is reloaded when subscribing to store.dispatch
我对 Ngrx 商店很陌生,但我有一个似乎有效的实现。
我注意到我正在构建的登录屏幕中有一个奇怪的行为。我想以特定方式处理 GetUserFailures,所以我订阅了 ScannedActionsSubject
并按操作类型进行过滤。
export class LoginComponent implements OnInit {
constructor(
private userService: UserService,
private store: Store<AppState>,
private actions$: ScannedActionsSubject,
) {
...
}
ngOnInit() {
this.actions$
.pipe(filter((action: any) => action.type === '[User] Get User Failure'))
.subscribe((action: any) => {
const error = action.payload.error.response;
this.handleError(error);
if (error && error.includes('not found')) {
this.snackBar.open('Sorry, we have no record of that email address.', 'OK');
} else if (error && error.includes('Invalid credentials')) {
this.snackBar.open('The password you entered is incorrect.', 'OK');
}
if (this.loading) this.loading = false;
});
}
async login(event: any) {
if (event) event.preventDefault();
// if the user is logging in for the first time, show update password form
if (this.validateForm(this.loginForm)) {
this.loading = true;
const email = this.loginForm.controls.email.value;
email && this.store.dispatch(new GetUserByEmail(email));
this.store.select(selectUserByEmail)
.pipe(filter(result => result.user !== (null || undefined)))
.subscribe(
async (result) => {
this.user = result.user;
if (this.user && this.user.status === 'Pending') {
const email = this.loginForm.controls.email.value;
const password = this.loginForm.controls.password.value;
email && password && this.userService.validatePasswordHash(email, password).subscribe(
(result) => {
if (result) {
this.loading = false;
this.loginStepper.selectedIndex = 2;
this.hidePassword = true;
}
},
(error) => {
this.handleError(error);
if (error.error && error.error.response.includes('Invalid credentials')) {
this.snackBar.open('The password you entered is incorrect.', 'OK');
this.loading = false;
return;
}
},
);
} else if (this.user && this.user.status === 'Active') {
localStorage.setItem('USER_AUTHD', 'true');
await this.router.navigateByUrl('/home');
this.snackBar.open(`Welcome back, ${this.user.recipientFullName.split(' ')[0]}!`, 'OK', { duration: 4000 });
} else {
console.log('neither active nor pending!', this.user);
}
this.loading = false;
return;
},
(error) => {
console.log('Error getting user by email', error);
return;
},
() => { // complete
if (this.loading) this.loading = false;
},
);
}
}
发生错误时,错误得到了正确处理,但是当我尝试再次启动我的登录过程时,store.select
部分无限期挂起,我似乎无法弄清楚原因。就可读性而言,它绝对不是最好的实现,但这是我为工作功能想出的全部。
重申一下,在第一次登录尝试失败后,每次登录尝试都会在登录流程中“挂起”,特别是 this.store.select(selectUserByEmail)
,但很难追踪挂起的原因,因为我只能看到至于 GetUserByEmail 的网络请求,它有效。
我希望能够“重新加载”系统以进行更多登录尝试。
GetUserByEmail 效果:
@Injectable()
export class UserEffects {
@Effect()
getUserByEmail$: Observable<any> = this.actions$.pipe(
ofType<GetUserByEmail>(UserActionsEnum.GetUserByEmail),
switchMap((action) => this.userService.getUserByEmail(action.payload)),
map((response) => new GetUserSuccess(response)),
catchError((error) => of(new GetUserFailure(error))),
);
}
减速器:
case UserActionsEnum.GetUserByEmail:
return {
...state,
user: action.payload?.data,
loading: false,
};
最初的问题是由于错误,效果将被取消订阅。所以你可以做的是在 switchMap
的内部 observable 中移动 catchError
:
...
switchMap(
(action) => this.userService.getUserByEmail(action.payload).pipe(catchError(...))
),
...
我对 Ngrx 商店很陌生,但我有一个似乎有效的实现。
我注意到我正在构建的登录屏幕中有一个奇怪的行为。我想以特定方式处理 GetUserFailures,所以我订阅了 ScannedActionsSubject
并按操作类型进行过滤。
export class LoginComponent implements OnInit {
constructor(
private userService: UserService,
private store: Store<AppState>,
private actions$: ScannedActionsSubject,
) {
...
}
ngOnInit() {
this.actions$
.pipe(filter((action: any) => action.type === '[User] Get User Failure'))
.subscribe((action: any) => {
const error = action.payload.error.response;
this.handleError(error);
if (error && error.includes('not found')) {
this.snackBar.open('Sorry, we have no record of that email address.', 'OK');
} else if (error && error.includes('Invalid credentials')) {
this.snackBar.open('The password you entered is incorrect.', 'OK');
}
if (this.loading) this.loading = false;
});
}
async login(event: any) {
if (event) event.preventDefault();
// if the user is logging in for the first time, show update password form
if (this.validateForm(this.loginForm)) {
this.loading = true;
const email = this.loginForm.controls.email.value;
email && this.store.dispatch(new GetUserByEmail(email));
this.store.select(selectUserByEmail)
.pipe(filter(result => result.user !== (null || undefined)))
.subscribe(
async (result) => {
this.user = result.user;
if (this.user && this.user.status === 'Pending') {
const email = this.loginForm.controls.email.value;
const password = this.loginForm.controls.password.value;
email && password && this.userService.validatePasswordHash(email, password).subscribe(
(result) => {
if (result) {
this.loading = false;
this.loginStepper.selectedIndex = 2;
this.hidePassword = true;
}
},
(error) => {
this.handleError(error);
if (error.error && error.error.response.includes('Invalid credentials')) {
this.snackBar.open('The password you entered is incorrect.', 'OK');
this.loading = false;
return;
}
},
);
} else if (this.user && this.user.status === 'Active') {
localStorage.setItem('USER_AUTHD', 'true');
await this.router.navigateByUrl('/home');
this.snackBar.open(`Welcome back, ${this.user.recipientFullName.split(' ')[0]}!`, 'OK', { duration: 4000 });
} else {
console.log('neither active nor pending!', this.user);
}
this.loading = false;
return;
},
(error) => {
console.log('Error getting user by email', error);
return;
},
() => { // complete
if (this.loading) this.loading = false;
},
);
}
}
发生错误时,错误得到了正确处理,但是当我尝试再次启动我的登录过程时,store.select
部分无限期挂起,我似乎无法弄清楚原因。就可读性而言,它绝对不是最好的实现,但这是我为工作功能想出的全部。
重申一下,在第一次登录尝试失败后,每次登录尝试都会在登录流程中“挂起”,特别是 this.store.select(selectUserByEmail)
,但很难追踪挂起的原因,因为我只能看到至于 GetUserByEmail 的网络请求,它有效。
我希望能够“重新加载”系统以进行更多登录尝试。
GetUserByEmail 效果:
@Injectable()
export class UserEffects {
@Effect()
getUserByEmail$: Observable<any> = this.actions$.pipe(
ofType<GetUserByEmail>(UserActionsEnum.GetUserByEmail),
switchMap((action) => this.userService.getUserByEmail(action.payload)),
map((response) => new GetUserSuccess(response)),
catchError((error) => of(new GetUserFailure(error))),
);
}
减速器:
case UserActionsEnum.GetUserByEmail:
return {
...state,
user: action.payload?.data,
loading: false,
};
最初的问题是由于错误,效果将被取消订阅。所以你可以做的是在 switchMap
的内部 observable 中移动 catchError
:
...
switchMap(
(action) => this.userService.getUserByEmail(action.payload).pipe(catchError(...))
),
...