【问题标题】:Why angular subscribes multiple times?为什么角度订阅多次?
【发布时间】:2018-12-20 05:20:54
【问题描述】:

我有这个结构:

  • product.service(用于服务)
  • 产品搜索组件(用于设置当前选中的对象)
  • compare-product 组件(用于订阅当前选中的对象)

我想在加载比较产品时订阅服务中的对象。一开始似乎还不错。但是,当我点击产品搜索的后退按钮,然后再次加载比较产品时,它订阅了两次。当我回去再次加载时,它被调用了三遍。返回,再次加载,调用四次,以此类推。

这些是代码:

服务:

//product.service
.......
private checkedSrc = new BehaviorSubject([]);
currentChecked = this.checkedSrc.asObservable();

.......
setChecked(checked: string[]){
    this.checkedSrc.next(checked);
}

resetChecked(){
    this.checkedSrc.next([]);
}
.......

产品搜索组件:

......
compare(){
    this.products_valid = true;
    this.productSvc.setChecked(this.checked);
    this.router.navigate(['compare']);
}
......

比较产品组件:

...
products: string[];
isLoading: boolean = true;

constructor(
  private productSvc: ProductsService
) { }

ngOnInit() {
  this.productSvc.currentChecked.subscribe(p => {this.products = p; console.log(this.products)})
}

我已经尝试过,但没有导航到比较组件。当我第一次调用 compare 函数时它订阅了一次,再次调用 compare 函数它订阅了两次,再次调用它订阅了 3 次,依此类推。

......
compare(){
    this.products_valid = true;
    this.productSvc.setChecked(this.checked);
    this.productSvc.currentChecked.subscribe(p =>{console.log(p);})
}
......

调用它的按钮:

<div class="row">
  <div class="col-md-6">
    <button class="btn btn-primary" style="margin-top: 20px;" (click)="compare()">Compare</button>
  </div>
</div>

我也尝试在每次调用 compare 方法时使用 resetChecked() 重置对象,但还是一样...

【问题讨论】:

  • 每次初始化组件时,您都会订阅它。为什么不应该订阅多次?当组件被销毁时,你应该取消订阅。

标签: angular rxjs


【解决方案1】:

当组件被销毁时,您需要取消订阅 observable。每次加载组件时,您都有 1 个订阅。

【讨论】:

  • 完美解决方案!!
【解决方案2】:

每当您致电subscribe 时,源(在这种情况下为checkSrc)都会收到新订阅者想要获取数据的通知。消息来源不知道您何时离开页面,它仍会跟踪一位订阅者。当您返回时,subscribe 再次被调用,现在源有两个订阅者。

您有多种选择来解决问题。第一个是在ngOnDestroy方法中取消订阅:

subscription;

ngOnInit() {
  this.subscription = this.productSvc.currentChecked.subscribe(p => {this.products = p; })
}

ngOnDestroy() {
  this.subscription.unsubscribe();
}

更好的选择是使用async 管道。

ngOnInit() {
 this.products = this.productSvc.currentChecked();
}

在您的 HTML 中:

<ul>
  <li *ngFor="let product of products | async">{{product.name}}</li>
</ul>

如您所见,this.products 不再指产品,而是指产品流。为了在您的模板中使用,您添加async 管道。优点之一是您不需要自己订阅和取消订阅。

【讨论】:

    【解决方案3】:

    在 Angular 6 中,如果您使用 ngOnDestroy 方法,请记住使用对订阅的引用。

    import { Subscription } from 'rxjs';
    export class MyComponent implements OnInit, OnDestroy {
    
      private subscription: Subscription //import from rxjs 
    
      constructor(private myService: MyService){}
    
      ngOnInit() {
        this.subscription = this.myService.myMethod.subscribe(...);
      }
    
      ngOnDestroy() {
        this.subscription.unsubscribe();
      }
    }
    

    如果在 ngOnDestroy 中,您直接在 this.myService.myMethod 上调用 unsubscribe,您最终会收到“ObjectUnsubscribedError”异常。

    【讨论】:

      猜你喜欢
      • 2021-08-25
      • 1970-01-01
      • 1970-01-01
      • 2021-01-10
      • 1970-01-01
      • 1970-01-01
      • 2018-12-24
      • 1970-01-01
      • 2019-06-18
      相关资源
      最近更新 更多