EventEmitter的正确用法是什么?

我读过类似于访问CustomHttp内部的EventEmitter服务的问题 用户在他的服务中使用EventEmitter,但他在评论

. {/p> .

我也读过这个 36014451 < a href = " https://stackoverflow.com/questions/36014395/angular-2-two-way-communication-between-components/36014451 " > < / >问题 这里的解决方案建议将EventEmitter传递给子节点并订阅它

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

369490 次浏览

博士TL;:

不要手动订阅它们,不要在服务中使用它们。按照文档中所示的方式使用它们,只用于在组件中触发事件。不要破坏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的正确用法。

是的,尽管用吧。

在最终的Angular核心API中,EventEmitter是一个公共的、文档化的类型。它是否基于Observable是不相关的;如果它记录的emitsubscribe方法适合你的需要,那么继续使用它。

正如文件中所述:

使用的处方。可观察对象,但提供了一个适配器,使其按此处指定的方式工作:https://github.com/jhusain/observable-spec

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

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

在很多情况下,使用发送特定类型事件的发射器是很有用的。如果这是你的用例,那就去做吧。如果/当他们链接到的规范的参考实现可用时,它应该是一个附带的替代品,就像任何其他填充材料一样。

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

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会触发一个事件,你需要使用事件发射器来触发。

如果不是亲子关系…然后你必须使用主题或通过公共服务。

no: nono和no: yesyes。 真相在中间 也没有理由因为Angular的下一个版本而害怕

从逻辑的角度来看,如果你有一个组件,你想要通知其他组件发生了什么事情,就应该触发一个事件,这可以用你(开发人员)认为应该做的任何方式来完成。我找不到不使用它的理由,也找不到不惜一切代价使用它的理由。同样,EventEmitter名称也向我暗示了一个正在发生的事件。我通常使用它来处理组件中发生的重要事件。我创建了服务,但在组件文件夹中创建了服务文件。因此,我的服务文件成为某种事件管理器或事件接口,因此我可以一目了然地确定可以在当前组件上订阅哪个事件。

我知道,也许我是一个老式的开发者。 但这不是事件驱动开发模式的一部分,这是你的特定项目的软件架构决策的一部分 有些人可能认为直接使用observable很酷。在这种情况下,直接使用可观察对象。 你不是连环杀手干的。除非你是一个精神变态的开发人员,到目前为止,程序是有效的,去做吧

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

如果组件之间是父-子关系,反之亦然,则使用@input &@输出事件发射器。

@output触发一个事件,你需要使用事件发射器触发。

如果不是亲子关系…然后你必须使用主题或通过公共服务

从纯实现的角度来看,因为emitsubscribeEventEmitter的公共接口的一部分,所以它们可以用于实现。

对于angular来说,如果它不想继承行为,则没有强制要求,Behaviour可以是EventEmitter类中的私有成员,类似于:

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

如果它继承了behavior,但行为不像,那么它违反了liskov's susbstitution principle