Angular EventEmitter多次调用

时间:2018-11-27 18:21:17

标签: angular angular-event-emitter

这真的很奇怪,很难解释。 我在某些服务中使用了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 应该只包含一项),但是如果打开控制台并看一下,将会看到每次您从一个视图返回并返回时,都会触发额外的时间。

  • 因此,第一次访问时,您将看到一次控制台输出。
  • 清除控制台并在视图之间移动,您将看到两次控制台输出。
  • 清除控制台并在视图之间移动,您将看到控制台输出三次。....

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

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

谁能告诉我为什么会这样以及如何阻止它?

2 个答案:

答案 0 :(得分:3)

这是因为您没有在组件销毁时杀死订阅(每次在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

答案 1 :(得分:0)

我有一个简短的方法可以解决您的问题

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();
    }
}