我花了一天时间与Angular2一起潜入RxJS,因为将用户界面建模为流的做法对我来说是新的。
我正在尝试提供用户对象流的用户服务。当用户通过身份验证时,将提供第一个User
对象。当用户更新时,可以提供额外的User
个对象,例如,他们更新了他们的档案如果在加载应用程序时未记录用户,或者他们注销,则会发出null
。
因此,组件中的观察器实现看起来像这样:
export class AppComponent {
private user: User;
private showLoginForm: boolean;
constructor(public userService: UserService) { }
ngOnInit() {
this.userService.user$.subscribe(user => {
this.user = user;
this.showLoginForm = this.user ? false : true;
})
}
}
userService.user$
可观察量是BehaviorSubject
类型。这是你如何实现这个?将null
发送到需要User
对象的流的想法并不适合我。但与此同时,它确实提供了回答问题的便捷方式:用户是否可用?
答案 0 :(得分:14)
"进行反应"真的需要成为一个全有或全无的东西,IMO。 This是一篇关于这个主题的最新文章。
具体来说,对于Angular2应用程序,这意味着您希望将内容模拟为无处不在,从端到端 - 从将数据传递到用于显示它的模板的HTTP响应。
所以在你的情况下,而不是:
@Component({
template: ` name: {{ user?.name }` //elvis operator always needed with this approach
})
export class AppComponent {
private user: User; // breaks the chain
ngOnInit() {
this.userService.user$.subscribe(user => {
this.user = user;
})
}
}
你想做的事情如下:
@Component({
template: ` name: {{ (user$ | async).name }` //let angular deal with that shit
})
export class AppComponent {
private user$: Observable<User>; // stream :)
private showLoginForm$: Observable<boolean>;
ngOnInit() {
this.user$ = this.userService.user$; //could actually be done in constructor
this.showLoginForm$ = this.user$.map(user => !user) //i.e. user ? false : true
}
}
这里需要注意的关键是,您将应用程序状态建模为从服务(可能是将可观察的API响应转发)到组件再到模板的整个流,您可以在其中利用{{ 3}}让angular处理订阅和更新UI的所有脏工作,以根据需要反映更改。
回应@MarkRajcok的评论:
说到subscribe()...你不需要在ngOnInit()的最后一行吗?
不,这实际上是一个重点。 AsyncPipe
的美妙之处在于,您不必须手动订阅任何内容,只需让Angular为您完成。这可以避开可能由于手动处理这些问题而引起的潜在变化检测问题的雷区。
但你如何处理错误?例如,假设当您尝试从后端获取用户时出现错误。如果你想使用NgIf显示错误或显示用户,你不必手动订阅()和&#34;打破链条&#34;?
不一定。 AsyncPipe
对于这些目的非常有用:
@Component({
template: ` <div>name: {{ (user$ | async).name }</div>
<div *ngIf="hasError$ | async">ERROR :("></div>`
})
export class AppComponent {
private user$: Observable<User>;
private showLoginForm$: Observable<boolean>;
private hasError$: Observable<boolean>;
private error$: Observable<string>;
ngOnInit() {
this.user$ = this.userService.user$;
this.showLoginForm$ = this.user$.map(user => !user)
this.hasError$ = this.user$.catch(error => true).startWith(false);
this.error$ = this.user$.catch(error => error.message);
}
}
话虽这么说,我的信息并不是手动订阅事物所必需的永远(当然有时候会有这种情况)而是我们的应该尽可能避免这样做。我用rx越舒服,我意识到这些情况越少。