RxJs 订阅者,传递空值? [英] RxJs subscribers, passing null values?

查看:23
本文介绍了RxJs 订阅者,传递空值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我花了一整天的时间用 Angular2 深入研究 RxJS,因为将用户界面建模为流的做法对我来说是新的.

I've spent the day diving into RxJS with Angular2, as the practice of modeling user interfaces as streams is new to me.

我正在试验提供用户对象流的用户服务.当用户通过身份验证时,将提供第一个 User 对象.当用户更新时,可能会提供额外的 User 对象,例如他们更新了他们的个人资料.如果用户在应用程序加载时未登录,或者他们注销,则发出 null.

I'm experimenting with a user service that provides a stream of User objects. The first User object will be provided when the user is authenticated. Additional User Objects may be provided when the User is updated, e.g. they update their profile. If the user is not logged when the application loads, or they logout, then null is emitted.

因此,组件中的观察者实现如下所示:

As such, an observer implementation in a component would look like this:

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$ observable 是一个 BehaviorSubject 类型.这是你将如何实现这一点?将 null 发送到需要 User 对象的流的想法并不适合我.但同时,它确实提供了一种方便的方式来回答这个问题:用户是否可用?

The userService.user$ observable is a BehaviorSubject type. Is this how you would implement this? The idea of sending null, to a stream that expects a User object, isn't sitting right with me. But at the same time, it does provide a convenient way to answer the question: is the User available or not?

推荐答案

反应式"确实需要成为一个要么全有要么全无的东西,IMO.这篇是一篇关于这个主题的近期非常好的文章.

"Going reactive" really needs to be an all-or-nothing thing, IMO. This is a really good recent article on this topic in general.

特别是关于 Angular2 应用程序,这意味着您希望将事物建模为流无处不在,从端到端 - 从提供数据的 HTTP 响应到用于显示它的模板.

With regard to Angular2 apps specifically, what this means is that you want to model things as streams everywhere, from end to end - from the HTTP responses that deliver data to the templates used to display it.

所以在你的情况下,而不是:

So in your case, rather than:

@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 响应)到组件再到模板的流,您可以在其中利用 AsyncPipe 让 angular 处理订阅和更新 UI 以根据需要反映更改的所有脏活.

The key thing to note here is you're modeling your application state as a stream all the way from the service (which presumably is relaying an observable API response) to the component to the template, where you leverage AsyncPipe to let angular deal with all the dirtywork of subscribing and updating the UI to reflect changes as needed.

回应@MarkRajcok 的评论:

In response to @MarkRajcok's comment:

说到 subscribe()... ngOnInit() 的最后一行不需要一个吗?

Speaking of subscribe()... don't you need one on your last line of ngOnInit()?

不,这实际上是一个重要的点.AsyncPipe 的美妙之处在于你不必手动订阅任何东西,让 Angular 为你做.这避开了可能因手动处理这些事情而产生的潜在变化检测问题的雷区.

No, and that's actually an important point. The beauty of AsyncPipe is that you don't have to manually subscribe to anything, just let Angular do it for you. This sidesteps a minefield of potential change-detection problems that can arise from handling these things manually.

但是你如何处理错误呢?例如,假设您在尝试从后端获取用户时遇到错误.如果你想用 NgIf 要么显示错误要么显示用户,难道你不需要手动 subscribe() 和断链"吗?

But how do you deal with errors? E.g., suppose you get an error when you try to get a user from the backend. If you want to use NgIf to either display an error or display the user, don't you have to manually subscribe() and "break the chain"?

不一定.Observable.catch()对于这些目的非常有用:

Not necessarily. Observable.catch() is quite useful for these purposes:

@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 越熟悉,我就越少意识到这些情况.

That being said, my message here isn't that it's never necessary to manually subscribe to things (of course there are situations when it is) but rather, that we should avoid doing it wherever possible. And the more comfortable I get with rx, the rarer I realize those situations are.

这篇关于RxJs 订阅者,传递空值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆