【问题标题】:Subject Subscription is triggered twice when I call .next() once in Angular app当我在 Angular 应用程序中调用 .next() 一次时,主题订阅被触发两次
【发布时间】:2019-05-27 11:28:37
【问题描述】:

我正在尝试创建一个可重用的 Modal 组件。 在 ModalService 中,我有一个主题,以及一个在主题上调用 next() 的方法。 ModalComponent 订阅了该主题,但无论何时调用服务中的方法,观察者的下一个函数都会触发两次。 有人知道这是什么原因吗?

export class ModalService { 
  openModal = new Subject(); 

  constructor() { } 

  open(cmp) { 
     this.openModal.next(cmp); 
   } 
}

模态组件:

export class ModalComponent implements OnInit {
  component: ComponentRef<any>;

  @ViewChild('entry', { read: ViewContainerRef }) entry: ViewContainerRef;

  constructor(
    private resolver: ComponentFactoryResolver,
    private modalService: ModalService
  ) {}

  ngOnInit() {
    this.modalService.openModal.subscribe(cmp => {

      // CALLD TWICE EVRY TIME THE SERVICE CALLS .next()
      console.log(cmp);
    });
  }

【问题讨论】:

    标签: javascript angular rxjs rxjs6 subject


    【解决方案1】:

    您的问题不清楚在哪里以及如何调用 open() 方法。是open() 调用了两次还是subscribe() 触发了两次?

    但如果您想与订阅者分享最后一个值,您可以在pipe() 中使用shareReplay(),如下所示:

    export class ModalService { 
      openModalSubject = new Subject(); 
      openModal = this.openModalSubject.asObservable().pipe(shareReplay());
      constructor() { } 
    
      open(cmp) { 
         this.openModalSubject.next(cmp); 
       } 
    }
    

    更新

    在您的模态组件中,您需要在从 observable 中导航时使用 unsubscribe。你可以通过两种方式做到这一点。

    第一种方式:

     modalSubscription: Subscription;
    
     ngOnInit() {
        this.modalSubscription = this.modalService.openModal.subscribe(cmp => {
    
          // CALLD TWICE EVRY TIME THE SERVICE CALLS .next()
          console.log(cmp);
        });
      }
    
      ngOnDestroy(){
        this.modalSubscription.unsubscribe();
      }
    

    第二种方式:

     unsubscribeSignal: Subject<void> = new Subject();
    
     ngOnInit() {
        this.modalSubscription = this.modalService.openModal
        .pipe(
           takeUntil(this.unsubscribeSignal.asObservable()),
        )
        .subscribe(cmp => {
    
          // CALLD TWICE EVRY TIME THE SERVICE CALLS .next()
          console.log(cmp);
        });
      }
    
      ngOnDestroy(){
        this.unsubscribeSignal.next();
      }
    

    我更喜欢第二种方式。这样,您可以一次取消订阅多个 observable。

    【讨论】:

    • 感谢您的回复!可以从应用程序中任何需要触发 Modal 的组件调用 open 方法。我尝试将此服务注入 AppComponent,并调用 modalService.open() 一次。由于某种原因,订阅被触发了两次。
    • 我试图在更新部分解释可能的原因。请看一看。如果你不取消订阅 observable 和 re-init modal 组件,它可能会触发两次。
    • 顺便说一句,我建议你进入这个经过良好测试的库的模态服务的源代码(ngx-bootstrap:Home PageGitHub)有一个更通用的观点.
    • 遇到了类似的问题,可以确认取消订阅 onDestroy 可以解决此问题。还请记住,当您的订阅被启动时,如果它的任何属性发生更改,onInit 这将(使用默认更改检测)将重绘您的组件。考虑为您的订阅使用 AfterViewInit,以避免在操作组件数据时调用任何不必要的函数。
    【解决方案2】:

    最好的方法是将数组中的所有订阅推送,然后取消订阅到 ngondestroy。

    First import the Subscription from rxjs
         import { Subscription} from 'rxjs';
        
    second create global property in component     
         subscriptions: Subscription[] = [];
        
        
    Third push all the subscribe in subscriptions property
        constructor(){
        this.subscriptions.push(this.Service.subject1.subscribe((result) => {
              console.log('subject1');
        
            }));
        
            this.subscriptions.push(this.dataService.subject2.subscribe((data) => {
            console.log('subject2')
        }
        
        
     Lastly unsubscribe it   
         ngOnDestroy() {
           
            this.subscriptions.forEach(sub => sub.unsubscribe());
        
        
          }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-01
      • 2018-03-16
      • 1970-01-01
      • 2019-09-22
      • 1970-01-01
      • 2020-03-15
      • 1970-01-01
      • 2018-08-18
      相关资源
      最近更新 更多