错误后可观察到 rx 损坏
Observable with rx broken after error
我正在尝试使用 ngrx store + ng effects 为我的应用程序编写登录流程。我设法编写了它并且它在快乐的场景中工作,但是当用户向表单输入错误的值时,服务器以 401 响应,下一次登录尝试无效。我已经读到在使用可观察对象时必须捕获异常以避免 'break' 流,但据我所知我捕获了异常并且它现在仍在工作。
代码下方;
export class LoginComponent {
logged = new Observable<any>();
constructor(private store: Store<AppStore>) {
this.logged = store.select('login');
}
login(username: string, password: string){
let body = JSON.stringify({username, password});
this.store.dispatch({type: LoginActions.ATTEMPT_LOGIN, payload: body});
}
}
@Injectable()
export class LoginEffects {
constructor(
private actions: Actions,
private loginService: LoginService
) { }
@Effect() login = this.actions
.ofType(LoginActions.ATTEMPT_LOGIN)
.map(toPayload)
.switchMap(payload => this.loginService.attemptLogin(payload))
.map(response => new LoginActions.LoginSuccess(response))
.catch(error => of(new LoginActions.LoginFailed(error)));
@Effect() success = this.actions
.ofType(LoginActions.LOGIN_SUCCESS)
.map(toPayload)
.map(payload => localStorage.setItem(Global.TOKEN, payload))
.map(() => go(['/menu']));
@Effect() error = this.actions
.ofType(LoginActions.LOGIN_FAILED)
.map(toPayload)
.map(payload => console.log(payload))
.ignoreElements();
}
export const login = (state: any = null, action: Actions) => {
switch (action.type) {
case LoginActions.ATTEMPT_LOGIN:
console.log('hello from reducer attempt login');
return action.payload;
case LoginActions.LOGIN_SUCCESS:
console.log('hello from reducer success login');
return action.payload;
case LoginActions.LOGIN_FAILED:
console.log('hello from reducer failed login');
return action.payload;
default:
return state;
}
};
@Injectable()
export class LoginService {
auth = new Observable<any>();
constructor(private store: Store<AppStore>, private http: Http) {
this.auth = store.select('auth');
}
attemptLogin(payload): Observable<any> {
// let body = JSON.stringify({username, password});
return this.http.post(Global.API_URL + '/login', payload)
.map(response => response.headers.get('Authorization'));
// .map(action => (
// { type: LoginActions.ATTEMPT_LOGIN, payload: action}))
// .subscribe(action => {this.store.dispatch(action);
// });
}
}
当捕获到错误时,catch
返回的可观察对象用于继续链。返回的 observable 完成,完成效果并看到 ngrx
取消订阅效果。
将 map
和 catch
移动到 switchMap
:
@Effect() login = this.actions
.ofType(LoginActions.ATTEMPT_LOGIN)
.map(toPayload)
.switchMap(payload => this.loginService.attemptLogin(payload)
.map(response => new LoginActions.LoginSuccess(response))
.catch(error => of(new LoginActions.LoginFailed(error)))
);
在 switchMap
内捕捉不会完成效果。
快乐之路场景:
错误场景:需要 reducer 来处理错误情况并在需要时向用户显示一些消息。
通过使用 rxjs/operators
中的 pipe
和 catchError
,我们可以将两个(或所有)错误情况重新映射到一个 ErrorAction 中,然后我们可以直接在 effects
并进行副作用 ui 更改。
@Effect() login = this.actions
.ofType(LoginActions.ATTEMPT_LOGIN)
.map(toPayload)
.switchMap(payload => this.loginService.attemptLogin(payload)
.map(response => new LoginActions.LoginSuccess(response))
.catch(error => of(new LoginActions.LoginFailed(error)))
);
我正在尝试使用 ngrx store + ng effects 为我的应用程序编写登录流程。我设法编写了它并且它在快乐的场景中工作,但是当用户向表单输入错误的值时,服务器以 401 响应,下一次登录尝试无效。我已经读到在使用可观察对象时必须捕获异常以避免 'break' 流,但据我所知我捕获了异常并且它现在仍在工作。
代码下方;
export class LoginComponent {
logged = new Observable<any>();
constructor(private store: Store<AppStore>) {
this.logged = store.select('login');
}
login(username: string, password: string){
let body = JSON.stringify({username, password});
this.store.dispatch({type: LoginActions.ATTEMPT_LOGIN, payload: body});
}
}
@Injectable()
export class LoginEffects {
constructor(
private actions: Actions,
private loginService: LoginService
) { }
@Effect() login = this.actions
.ofType(LoginActions.ATTEMPT_LOGIN)
.map(toPayload)
.switchMap(payload => this.loginService.attemptLogin(payload))
.map(response => new LoginActions.LoginSuccess(response))
.catch(error => of(new LoginActions.LoginFailed(error)));
@Effect() success = this.actions
.ofType(LoginActions.LOGIN_SUCCESS)
.map(toPayload)
.map(payload => localStorage.setItem(Global.TOKEN, payload))
.map(() => go(['/menu']));
@Effect() error = this.actions
.ofType(LoginActions.LOGIN_FAILED)
.map(toPayload)
.map(payload => console.log(payload))
.ignoreElements();
}
export const login = (state: any = null, action: Actions) => {
switch (action.type) {
case LoginActions.ATTEMPT_LOGIN:
console.log('hello from reducer attempt login');
return action.payload;
case LoginActions.LOGIN_SUCCESS:
console.log('hello from reducer success login');
return action.payload;
case LoginActions.LOGIN_FAILED:
console.log('hello from reducer failed login');
return action.payload;
default:
return state;
}
};
@Injectable()
export class LoginService {
auth = new Observable<any>();
constructor(private store: Store<AppStore>, private http: Http) {
this.auth = store.select('auth');
}
attemptLogin(payload): Observable<any> {
// let body = JSON.stringify({username, password});
return this.http.post(Global.API_URL + '/login', payload)
.map(response => response.headers.get('Authorization'));
// .map(action => (
// { type: LoginActions.ATTEMPT_LOGIN, payload: action}))
// .subscribe(action => {this.store.dispatch(action);
// });
}
}
当捕获到错误时,catch
返回的可观察对象用于继续链。返回的 observable 完成,完成效果并看到 ngrx
取消订阅效果。
将 map
和 catch
移动到 switchMap
:
@Effect() login = this.actions
.ofType(LoginActions.ATTEMPT_LOGIN)
.map(toPayload)
.switchMap(payload => this.loginService.attemptLogin(payload)
.map(response => new LoginActions.LoginSuccess(response))
.catch(error => of(new LoginActions.LoginFailed(error)))
);
在 switchMap
内捕捉不会完成效果。
快乐之路场景:
错误场景:需要 reducer 来处理错误情况并在需要时向用户显示一些消息。
通过使用 rxjs/operators
中的 pipe
和 catchError
,我们可以将两个(或所有)错误情况重新映射到一个 ErrorAction 中,然后我们可以直接在 effects
并进行副作用 ui 更改。
@Effect() login = this.actions
.ofType(LoginActions.ATTEMPT_LOGIN)
.map(toPayload)
.switchMap(payload => this.loginService.attemptLogin(payload)
.map(response => new LoginActions.LoginSuccess(response))
.catch(error => of(new LoginActions.LoginFailed(error)))
);