共享时的角度可观察到的行为很奇怪 [英] Angular observable behavior odd when shared

查看:82
本文介绍了共享时的角度可观察到的行为很奇怪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以观察到,当我使用rxjs的"share"运算符时,在Angular模板中的行为会很奇怪.这是我(在服务中)设置两个可观察对象的方法:

this.family = this.store.select(getFamily).pipe(
  tap(family => {
    if (family == null) {
      this.loadFamily();
    }
  }),
  filter(family => family != null),
  share(),
);
this.familyMembers = this.family.pipe(
  map(family => {
    return family.familyMembers;
  })
);

然后我将可观察到的familyMember作为属性添加到我的组件中

this.familyMembers = this.familyService.familyMembers

我的标记看起来像这样:

 <tbody *ngIf="(familyMembers | async) != null">
        <pre> {{(familyMembers | async) | json}}</pre>

现在奇怪的是,当填充familyMembers(两个数组)时,即使我已经使用*ngIf检查了null,<pre>也会在内部显示null.

我还有一个列表,该列表不呈现任何内容,如下所示:

<ng-template ngFor let-familyMember let-i="index" [ngForOf]="(familyMembers | async)" [ngForTrackBy]="trackByFn">

我知道familyMembers可观察到的最后一件事是正确的两个家庭成员,我已经用mapconsole.log进行了检查. Angular模板似乎将其视为null ..但不是吗?

如果我从可观察到的系列中删除了share(),但一切正常,但tap()运行了两次,这是不希望的.

使用shareReplay()而不是share()解决了我的问题.当所有订阅都取消订阅时,share()不会重新发送值.

解决方案

您应该使用shared()运算符,因为您两次订阅,所以才得到重复的.
您应该相应地更改html代码:

 <tbody *ngIf="familyMembers | async as familyProps">
        <pre> {{familyProps | json}}</pre> 

在第一个* ng中,如果您检查值的存在,则无需在另一行中再次使用异步管道,因为如果未通过第一个异步管道,则不会调用它.
另外,当您调用"as familyProps"并在下一行中使用它时,请确保在执行此行时此本地对象将可用.如果没有'as',它可能会起作用,但是根据您的评论,我只是添加来确保它.

-编辑
您调用的每个异步管道也将进行订阅,现在发生的情况是第一行带有* ngIf等待值,第二行位于此包装器内,因此它将在第一行执行之前不会调用.
现在,当第一行通过时,由于第一行预订和shared()运算符,第二行将尝试使用异步管道进行预订,但它已经完成.
您可以尝试一下,它也应该可以正常工作:

<tbody *ngIf="familyMembers | async">
  <pre> {{familyMembers | json}} </pre> 

I have an observable that when I use the rxjs 'share' operator behaves strangely in the Angular template. Here's how I setup my two observables (in a service):

this.family = this.store.select(getFamily).pipe(
  tap(family => {
    if (family == null) {
      this.loadFamily();
    }
  }),
  filter(family => family != null),
  share(),
);
this.familyMembers = this.family.pipe(
  map(family => {
    return family.familyMembers;
  })
);

I then add the familyMember observable to my component as a property

this.familyMembers = this.familyService.familyMembers

My markup looks something like this:

 <tbody *ngIf="(familyMembers | async) != null">
        <pre> {{(familyMembers | async) | json}}</pre>

Now the strange thing is when familyMembers is populated (an array of two), the <pre> will render with null inside even after i've checked for null with the *ngIf.

I also have a list that does not render anything as follows:

<ng-template ngFor let-familyMember let-i="index" [ngForOf]="(familyMembers | async)" [ngForTrackBy]="trackByFn">

I know that the last thing familyMembers observable emitted was the correct two family members, I've checked this with map and console.log. The Angular template seems to be seeing this as null.. but also not?

Everything works if I remove the share() from the family observable but the tap() runs twice which is not desirable.

EDIT:

Using shareReplay() instead of share() fixed my problem. share() will not re-emit values when all subscriptions unsubscribe.

解决方案

You should use the shared() operator since you are subscribe twice, that's why you got the duplicate.
You should change your html code accordingly :

 <tbody *ngIf="familyMembers | async as familyProps">
        <pre> {{familyProps | json}}</pre> 

In the first *ngIf you check for the existence of the values, so there is no need to use async pipe again in the other row since it won't be called if its not passed the first one.
Plus, when you calling 'as familyProps' and using it in the next line, you are sure that this local object will be available when this line executes. It might work without the 'as', but from your comment, I just add it to make sure.

--EDIT
Each async pipe that you call will subscribe too, now what happen is that the first line with *ngIf waiting for the values, and the second line located inside this wrapper, so it won't call until the first line executes.
Now, when the first line pass, the second line will try to subscribe with the async pipe but its already completes, because of the first line subscription and the shared() operator.
You can try this, and it should work as well:

<tbody *ngIf="familyMembers | async">
  <pre> {{familyMembers | json}} </pre> 

这篇关于共享时的角度可观察到的行为很奇怪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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