【问题标题】:Angular EventEmitter called multiple times多次调用 Angular EventEmitter
【发布时间】:2019-04-29 13:25:55
【问题描述】:

这真的很奇怪,很难解释。 我在一些服务中使用了EventEmitter,并且一直在使用它来更改我的视图数据。 我遇到了更改路线(通过链接或通过历史返回)的问题,它似乎被多次触发,因此它搞乱了我的逻辑。

所以我在 stackblitz 上创建了一个测试,看看我是否可以重新创建它。 我做了一个简单的服务:

import { Injectable, Output, EventEmitter } from '@angular/core';

@Injectable()
export class ListService {
@Output() listChanged: EventEmitter<any[]> = new EventEmitter<any[]>()

  constructor() { }

  list() {
    this.listChanged.emit([]);
  }
}

然后在我的一条路线中,我只是这样做:

import { Component, OnInit } from '@angular/core';

import { ListService } from '../list.service';

@Component({
  selector: 'app-products',
  templateUrl: './products.component.html',
  styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {
  count: any[] = []

  constructor(
    private listService: ListService
  ) { }

  ngOnInit() {
    this.listService.listChanged.subscribe(() => {
      this.count.push('invoked');
      console.log('invoked');
      console.log('------');
    });
    this.listService.list();
  }
}

然后我创建了一个像这样的简单模板:

<p>
  Invoke should only be called once
</p>

<ul>
  <li *ngFor="let item of count">{{ item }}</li>
</ul>

当您在路由之间导航时,它看起来像预期的那样工作(ngFor 应该只有一个项目),但是如果您打开控制台并查看一下,您会看到每次从一个视图返回时,都会触发额外的时间。

  • 所以,第一次访问你会看到控制台输出一次。
  • 清除控制台并在视图之间移动,您将看到控制台输出两次。
  • 清除控制台并在视图之间移动,您将看到控制台输出 3 次.....

每次交换视图时都会发生这种情况。 这是 stackblitz 链接,您可以自己查看。

https://stackblitz.com/edit/angular-sthags

谁能告诉我为什么会发生这种情况以及如何阻止它?

【问题讨论】:

    标签: angular angular-event-emitter


    【解决方案1】:

    这是因为您在组件销毁时并未终止订阅(每次您的 Products 组件初始化时都会创建新订阅,从而导致内存泄漏)

    将订阅分配给类变量,使用ngOnDestroy() 挂钩终止订阅。

    subsVar: Subscription;
    
    ngOnInit() {
        this.subsVar = this.listService.listChanged.subscribe(() => {
          this.count.push('invoked');
          console.log('invoked');
          console.log('------');
        });
    }
    
    ngOnDestroy() {
       if (this.subsVar) {
          this.subsVar.unsubscribe()
        }
    }
    

    https://stackblitz.com/edit/angular-9rvxgv?file=src/app/products/products.component.ts

    【讨论】:

      【解决方案2】:

      我有一个捷径可以解决你的问题

      export class ProductsComponent implements OnInit {
          count: any[] = [];
          isAlowToSub: boolean = true;
      
          constructor(
              private listService: ListService
          ) { }
          
          ngOnInit() {
              this.listService.listChanged.subscribe(() => {
                  if(this.isAlowToSub == true)
                  {
                      this.count.push('invoked');
                      console.log('invoked');
                      console.log('------');
                      this.isAlowToSub = false;
                  }
              });
              this.listService.list();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-27
        • 1970-01-01
        • 2020-01-19
        • 1970-01-01
        • 2019-03-26
        • 1970-01-01
        • 2023-03-04
        • 2012-08-22
        相关资源
        最近更新 更多