我在CustomHttp中读过类似访问EventEmitter Service的问题 用户在他的服务中使用EventEmitter,但他在这个评论中被建议 不使用它,而是直接在他的服务中使用Observables。
我也读过这个 问题 解决方案建议将EventEmitter传递给子进程并订阅它。
我的问题是:我是否应该手动订阅EventEmitter?我该如何使用它?
我在CustomHttp中读过类似访问EventEmitter Service的问题 用户在他的服务中使用EventEmitter,但他在这个评论中被建议 不使用它,而是直接在他的服务中使用Observables。
我也读过这个 问题 解决方案建议将EventEmitter传递给子进程并订阅它。
我的问题是:我是否应该手动订阅EventEmitter?我该如何使用它?
当前回答
是的,尽管用吧。
EventEmitter是一个在最终的Angular核心API中文档化的公共类型。它是否基于可观察对象无关紧要;如果它记录的emit和subscribe方法适合您的需要,那么就使用它。
正如文件中所述:
使用的处方。可观察对象,但提供了一个适配器,使其按此处指定的方式工作:https://github.com/jhusain/observable-spec 一旦该规范的参考实现可用,就切换到它。
所以他们想要一个类似于Observable的对象,以某种方式表现,他们实现了它,并将其公开。如果它只是一个不应该被使用的Angular内部抽象,他们就不会公开它。
在很多情况下,使用发送特定类型事件的发射器是很有用的。如果这是你的用例,那就去做吧。如果/当他们链接到的规范的参考实现可用时,它应该是一个附带的替代品,就像任何其他填充材料一样。
只要确保传递给subscribe()函数的生成器遵循链接规范。返回的对象保证有一个unsubscribe方法,应该调用该方法来释放对生成器的任何引用(这目前是一个RxJs订阅对象,但这确实是一个不应该依赖的实现细节)。
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评论。
其他回答
当你想要组件交互时,你需要知道什么是@Input, @Output, EventEmitter和Subjects。
如果组件之间的关系是父子关系,反之亦然,我们使用@input & @output与事件发射器。
@output会触发一个事件,你需要使用事件发射器来触发。
如果不是亲子关系…然后你必须使用主题或通过公共服务
当你想进行跨组件交互时,你需要知道什么是@Input, @Output, EventEmitter和Subjects。
如果组件之间的关系是父子关系,反之亦然,我们使用@input & @output与事件发射器。
@output会触发一个事件,你需要使用事件发射器来触发。
如果不是亲子关系…然后你必须使用主题或通过公共服务。
是的,尽管用吧。
EventEmitter是一个在最终的Angular核心API中文档化的公共类型。它是否基于可观察对象无关紧要;如果它记录的emit和subscribe方法适合您的需要,那么就使用它。
正如文件中所述:
使用的处方。可观察对象,但提供了一个适配器,使其按此处指定的方式工作:https://github.com/jhusain/observable-spec 一旦该规范的参考实现可用,就切换到它。
所以他们想要一个类似于Observable的对象,以某种方式表现,他们实现了它,并将其公开。如果它只是一个不应该被使用的Angular内部抽象,他们就不会公开它。
在很多情况下,使用发送特定类型事件的发射器是很有用的。如果这是你的用例,那就去做吧。如果/当他们链接到的规范的参考实现可用时,它应该是一个附带的替代品,就像任何其他填充材料一样。
只要确保传递给subscribe()函数的生成器遵循链接规范。返回的对象保证有一个unsubscribe方法,应该调用该方法来释放对生成器的任何引用(这目前是一个RxJs订阅对象,但这确实是一个不应该依赖的实现细节)。
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评论。
TL; diana:
不要手动订阅它们,不要在服务中使用它们。按照文档中所示的方式使用它们,只用于在组件中触发事件。不要破坏angular的抽象。
答:
不,您不应该手动订阅它。
EventEmitter是一个angar2抽象,它的唯一目的是在组件中发射事件。引用Rob Wormald的评论
[…EventEmitter实际上是Angular的一个抽象,应该只用于在组件中发射自定义事件。否则,就像使用其他库一样使用Rx。
这在EventEmitter的文档中说得很清楚。
使用by指令和组件来发出自定义事件。
使用它有什么问题?
Angular2永远不会保证EventEmitter将继续是一个可观察对象。因此,这意味着如果代码发生变化,就要重构它。我们必须访问的唯一API是它的emit()方法。我们永远不应该手动订阅EventEmitter。
以上所说的一切在这篇Ward Bell的评论中都更清楚了(建议阅读这篇文章,以及该评论的答案)。引用参考
不要指望EventEmitter继续是一个可观察对象! 不要指望将来会有那些可观察的操作符! 这些将很快被弃用,并可能在发布前删除。 仅在子组件和父组件之间的事件绑定时使用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的正确用法。
从纯实现的角度来看,因为emit和subscribe是EventEmitter公共接口的一部分,所以可以将它们用于实现。
对于angular来说,如果它不想要的话,没有强制从行为中继承,行为可以是EventEmitter类中的私有成员,比如,
public class EventEmitter{
private _behaviour=new Subject<void>();
private _behaviour$=this._behaviour.asObservable();
......
public emit(){
_behaviour.emit();
}
....
}
如果它继承了行为,但行为不像行为,则违反了利斯科夫替换原理。