277

我已经阅读了诸如Access EventEmitter Service inside of CustomHttp 之类的问题 ,其中用户在其服务中使用 EventEmitter,但在此评论中建议他 不要使用它,而是直接在他的服务中使用 Observables。

我还阅读了这个 问题 ,其中解决方案建议将 EventEmitter 传递给孩子并订阅它。

那么我的问题是:我应该,还是不应该手动订阅 EventEmitter?我应该如何使用它?

4

6 回答 6

396

TL;博士

不,不要手动订阅它们,不要在服务中使用它们。如文档中所示使用它们仅在组件中发出事件。不要打败 Angular 的抽象。

回答:

不,您不应该手动订阅它。

EventEmitter是一个 angular2 抽象,它的唯一目的是在组件中发出事件。引用Rob Wormald的评论

[...] EventEmitter 实际上是一个 Angular 抽象,并且应该仅用于在组件中发出自定义事件。否则,只需像使用任何其他库一样使用 Rx。

这在 EventEmitter 的文档中说得很清楚。

由指令和组件使用以发出自定义事件。

使用它有什么问题?

Angular2 永远不会保证 EventEmitter 将继续成为 Observable。所以这意味着如果我们的代码发生变化,就要重构它。我们必须访问的唯一 API 是它的emit()方法。我们永远不应该手动订阅 EventEmitter。

上述所有内容在此 Ward Bell 的评论中更加清楚(建议阅读该文章以及该评论的答案)。报价参考

不要指望 EventEmitter 继续成为 Observable!

不要指望那些 Observable 运算符将来会出现!

这些将很快被弃用,并可能在发布前被删除。

仅将 EventEmitter 用于子组件和父组件之间的事件绑定。不要订阅它。不要调用任何这些方法。只打电话eve.emit()

他的评论与罗布很久以前的评论一致。

那么,如何正确使用呢?

只需使用它从您的组件中发出事件。看看下面的例子。

@Component({
    selector : 'child',
    template : `
        <button (click)="sendNotification()">Notify my parent!</button>
    `
})
class Child {
    @Output() notifyParent: EventEmitter<any> = new EventEmitter();
    sendNotification() {
        this.notifyParent.emit('Some value to send to the parent');
    }
}

@Component({
    selector : 'parent',
    template : `
        <child (notifyParent)="getNotification($event)"></child>
    `
})
class Parent {
    getNotification(evt) {
        // Do something with the notification (evt) sent by the child!
    }
}

怎么不使用?

class MyService {
    @Output() myServiceEvent : EventEmitter<any> = new EventEmitter();
}

停在那里……你已经错了……

希望这两个简单的例子能够阐明 EventEmitter 的正确用法。

于 2016-03-18T05:20:38.550 回答
126

是的,继续使用它。

EventEmitter是最终 Angular Core API 中的一个公开的、记录在案的类型。是否基于Observable无关紧要;如果它的文档emitsubscribe方法适合您的需要,请继续使用它。

正如文档中所述:

使用 Rx.Observable 但提供了一个适配器以使其按照此处指定的方式工作:https ://github.com/jhusain/observable-spec

一旦规范的参考实现可用,切换到它。

所以他们想要一个Observable以某种方式表现的类似对象,他们实现了它,并将其公开。如果它只是一个不应该使用的内部 Angular 抽象,他们就不会公开它。

很多时候,拥有一个发送特定类型事件的发射器很有用。如果那是您的用例,那就去做吧。如果/当他们链接到的规范的参考实现可用时,它应该是一个直接替换,就像任何其他 polyfill 一样。

只要确保您传递给subscribe()函数的生成器遵循链接的规范。返回的对象保证有一个unsubscribe方法,应该调用该方法来释放对生成器的任何引用(这当前是一个RxJsSubscription对象,但这确实是一个不应该依赖的实现细节)。

export class MyServiceEvent {
    message: string;
    eventId: number;
}

export class MyService {
    public onChange: EventEmitter<MyServiceEvent> = new EventEmitter<MyServiceEvent>();

    public doSomething(message: string) {
        // do something, then...
        this.onChange.emit({message: message, eventId: 42});
    }
}

export class MyConsumer {
    private _serviceSubscription;

    constructor(private service: MyService) {
        this._serviceSubscription = this.service.onChange.subscribe({
            next: (event: MyServiceEvent) => {
                console.log(`Received message #${event.eventId}: ${event.message}`);
            }
        })
    }

    public consume() {
        // do some stuff, then later...

        this.cleanup();
    }

    private cleanup() {
        this._serviceSubscription.unsubscribe();
    }
}

所有措辞强硬的厄运和悲观预测似乎都源于单个开发人员对 Angular 2 预发布版本的单个 Stack Overflow 评论。

于 2017-11-07T20:46:41.037 回答
6

当你想要进行跨组件交互时,你需要知道什么是 @Input 、 @Output 、 EventEmitter 和 Subjects 。

如果组件之间的关系是父子关系,反之亦然,我们将@input & @output 与事件发射器一起使用。

@output 发出一个事件,您需要使用事件发射器发出。

如果不是父子关系..那么您必须使用主题或通过公共服务。

于 2019-04-27T10:09:42.853 回答
2

当你想要组件交互时,你需要知道 @Input 、 @Output 、 EventEmitter 和 Subjects 是什么。

如果组件之间的关系是父子关系,反之亦然,我们将@input & @output 与事件发射器一起使用。

@output发出一个事件,您需要使用事件发射器发出。

如果不是父子关系..那么您必须使用主题或通过公共服务

于 2021-03-19T12:04:23.027 回答
1

没有:nono 和 no:是的。事实就在中间,没有理由因为 Angular 的下一个版本而感到害怕。

从逻辑的角度来看,如果您有一个组件并且您想通知其他组件发生了某事,则应该触发一个事件,并且可以通过您(开发人员)认为应该完成的任何方式来完成。我看不出不使用它的原因,也看不出不惜一切代价使用它的原因。EventEmitter 的名称也向我暗示了一个正在发生的事件。我通常将它用于组件中发生的重要事件。我创建了服务,但在组件文件夹中创建了服务文件。所以我的服务文件变成了一种事件管理器或事件接口,所以我一眼就能看出我可以在当前组件上订阅哪个事件。

我知道..也许我是一个老式的开发人员。但这不是事件驱动开发模式的一部分,这是您特定项目的软件架构决策的一部分。

其他一些人可能认为直接使用 Observables 很酷。在这种情况下,直接使用 Observables。你不是这样做的连环杀手。除非您是精神病患者开发人员,否则到目前为止该程序有效,请执行此操作。

于 2019-06-06T11:44:34.577 回答
0

从纯实现的角度来看,由于emitsubscribe是 的公共接口的一部分EventEmitter,它们可以用于实现。

对于 Angular,如果它不想继承行为,则没有强制继承,Behaviour可能是EventEmitter类中的私有成员,例如,

public class EventEmitter{
  private _behaviour=new Subject<void>();
  private _behaviour$=this._behaviour.asObservable();
  ......
  public emit(){
    _behaviour.emit();
  }
  ....
}

如果它继承自 Behvaiour 但行为不像一个,那么它违反了liskov's susbstitution principle.

于 2021-10-21T07:54:40.493 回答