EventEmitter的正确用法是什么?

Eri*_*nez 199 angular2-services angular

我已经在CustomHttp 中读取了Access EventEmitter Service等问题,其中用户在其服务中使用了EventEmitter,但是他在本评论中建议他 不要使用它,而是直接在他的服务中使用Observables.

我还阅读了这个 问题 ,解决方案建议将EventEmitter传递给子节点并订阅它.

我的问题是:我应该,还是不应该手动订阅EventEmitter?我该怎么用?

Eri*_*nez 311

不,你不应该手动订阅它.

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

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

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

指令和组件使用它来发出自定义事件.

使用它有什么问题?

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

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

不要指望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!
    }
}
Run Code Online (Sandbox Code Playgroud)

怎么不用呢?

class MyService {
    @Output() myServiceEvent : EventEmitter<any> = new EventEmitter();
}
Run Code Online (Sandbox Code Playgroud)

停在那儿......你已经错了......

希望这两个简单的例子能够澄清EventEmitter的正确用法.

TL; DR回答:

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

  • @Eric当你写下这个答案时,你写道:'这些将很快被弃用,可能在发布前被删除',引用Ward Bell.但这是2年前所说的,现在我们有角度6.这句话现在还适用吗?我继续在官方文档中看到EventEmitter仍然有subscribe()方法,所以我认为如果谷歌想要停止以Rxjs主题为基础,他们就已经完成了它.所以你认为你原来的答案仍然适合当前的Angular状态吗? (7认同)
  • 对托比最近的答案有何评论?我猜他的答案应该是现在被接受的答案. (5认同)

Tob*_*s J 86

是的,继续使用它.

EventEmitter是最终Angular Core API中的公共文档类型.它是否基于Observable无关紧要; 如果它的记录emitsubscribe方法适合您的需要,那么继续使用它.

正如文档中所述:

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

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

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

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

请确保传递给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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我们现在使用的是Angular v6,并且没有弃用或删除EventEmmiter所以我说它可以安全使用.但是,我确实看到了学习如何使用RxJS的Observables的好处. (6认同)
  • 这听起来很合理 - 其他人都想对此进行权衡吗?subscribe毕竟是一个关于事件发射器的公共方法? (2认同)

Akh*_*hil 5

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

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

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

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