EventEmitter的正确用法是什么?

时间:2016-03-18 05:20:39

标签: angular angular2-services

我读过像Access EventEmitter Service inside of CustomHttp这样的问题 用户在其服务中使用EventEmitter的地方,但在comment { 不要使用它,而是直接在他的服务中使用Observables。

我也读过这个 question 解决方案建议将EventEmitter传递给子节点并订阅它。

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

5 个答案:

答案 0 :(得分:293)

不,您不应手动订阅它。

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

  

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

在EventEmitter的文档中说明了这一点。

  

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

使用它有什么问题?

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

上述所有内容在此Ward Bell comment中更为明确(建议阅读文章,以及该评论的answer)。引用以供参考

  

不要指望EventEmitter继续成为Observable!

     

不要指望将来会有那些Observable运营商!

     

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

     

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

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

那么,如何正确使用它?

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

@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的正确用法。

TL; DR 回答:

不,不要手动订阅它们,不要在服务中使用它们。仅按文档中的说明使用它们以在组件中发出事件。不要打败角度的抽象。

答案 1 :(得分:74)

是的,继续使用它。

EventEmitter是最终Angular Core API中的public, documented type。它是否基于Observable是无关紧要的;如果其记录的emitsubscribe方法符合您的需要,请继续使用。

正如文档中所述:

  

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

     

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

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

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

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

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评论。

答案 2 :(得分:1)

如果要进行跨组件交互,则需要知道什么是@Input,@Output,EventEmitter和Subjects。

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

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

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

答案 3 :(得分:1)

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

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

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

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

答案 4 :(得分:-1)

从非常合乎逻辑的角度来看。如果您有一个组件,并且想要通知其他组件某些事情发生了,则应该触发一个事件。我不明白为什么不使用它的原因。同样EventEmitter的名称也向我暗示了正在发生的事件。我通常将其用于Component范围内发生的重要事件。我创建了服务,但是在组件文件夹中创建了服务文件。这样我的服务文件就变成了一种事件管理器或事件接口,因此我一眼就能确定可以在当前组件上订阅哪个事件。

我知道。也许我是个老迷。

但这被称为:事件驱动开发模式。

其他一些人可能认为Observables很酷。在这种情况下,请继续使用Observables。 到目前为止,您还不是杀人犯,但程序可以做到。

没有:nono,没有:是的。