订阅被调用两次

Posted

技术标签:

【中文标题】订阅被调用两次【英文标题】:Subscribe is called twice 【发布时间】:2018-10-01 09:51:18 【问题描述】:

我正在尝试创建一个表单来提交详细信息,但是当我订阅服务时,订阅完成了两次。首先是空数据,其次是实际数据。

组件.ts

addBook() 
    this.errorMessage = null;
    this.fireService.getBook(this.bookDetails.isbn).subscribe(data => 
      console.log('subscribe called');
      if (null != data) 
        this.dbox.open(DialogBoxComponent, 
          data:  title: 'Error', content: 'Book is already present in Library. Select Edit book to modify the details', button: false 
        );
        this.errorMessage = 'Book is already present in Library. Select Edit book to modify the details';
       else 
        this.fireService.addBook(this.bookDetails);
        this.dbox.open(DialogBoxComponent, 
          data:  title: 'Success', content: 'Book has been Added to Database', button: false 
        );
        this.router.navigateByUrl('/add-book');
      
    );
  

服务.ts

getBook(id) 
  console.log('called firebase get book');
  return this.db.doc(`/books/$id`).valueChanges();

下面是来自 chrome 控制台的图像。这表明订阅被调用了两次,而不是 firebase 服务。

Chrome console logs: Image please click to view

chrome 控制台日志

called firebase get book
subscribe called
subscribe called

请帮忙

【问题讨论】:

试试this.fireService.getBook(this.bookDetails.isbn).pipe(filter(data => !!data)).subscribe(...) @ChauTran 尝试了您的建议,我收到错误提示“void”类型的“this”上下文不可分配给“Observable”类型的方法的“this”。 可能是因为我使用的是pipable methods。对不起,忘了问你正在运行什么版本的 angular/rxjs。运行.filter(data => !!data) 的行为方式也应该相同;) 【参考方案1】:

这是因为当 Books 集合发生变化时,getBooks 返回的 observable 会发出一个新值。第一次没有相同 isbn 的书,所以数据为空。然后你添加一本书,same observable 再次触发,这次是你刚刚添加的书

如果您只想获取一次数据, 您可以使用 take 只订阅一次。

this.fireService.getBook(this.bookDetails.isbn).take(1).subscribe(data => 
  console.log('subscribe called');

【讨论】:

通过这种方式(使用take或first)观察者完成,他不会再得到任何数据 试过它说属性'take'不存在于类型'Observable @RezaRahmati 确实如此,但它的编码方式我假设他每次单击按钮时都会调用 addBook。该 observable 不用于显示实时列表 是的@David,我在单击按钮时调用该函数 @Abhijith 尝试导入 take 操作符import 'rxjs/add/operator/take';【参考方案2】:

就像 Chau Tran 所说,您可以过滤以获得有效响应。如果您还没有,我会添加一种取消订阅的方式。在下面的代码中,this.alive 是一个为真的字段,在 OnDestory 生命钩子中变为假。

this.fireService.getBook(this.bookDetails.isbn)
.takeWhile(() => this.alive)
.filter(data => !!data)
.subscribe(...)

【讨论】:

还有另一种方法可以通过使用新主题来取消它。这是链接。betterprogramming.pub/rxjs-best-practices-7f559d811514【参考方案3】:

在函数addBook 中,您正在调用订阅。每次调用addBook 函数时,您都在进行订阅调用,请避免在此类函数中使用订阅。确保只订阅onInit(),以便在您进行更改时进行检查。

【讨论】:

以上是关于订阅被调用两次的主要内容,如果未能解决你的问题,请参考以下文章

如何在 ngOnInit 上订阅两次?

Angular 2服务订阅了两次[重复]

Firebase 身份验证被调用两次

为啥 ngAfterContentInit 钩子被调用两次?

为啥 ngOnInit 被调用两次?

目标动作被调用两次