¿Cuál es el uso adecuado de un EventEmitter?

Resuelto Eric Martinez asked hace 8 años • 5 respuestas

He leído preguntas como Acceder al servicio EventEmitter dentro de CustomHttp donde el usuario usa EventEmitter en su servicio, pero en este comentario se le sugirió que no lo use y que en su lugar use Observables directamente en sus servicios.

También leí esta pregunta donde la solución sugiere pasar EventEmitter al niño y suscribirse a él.

Mi pregunta entonces es: ¿Debería o no suscribirme manualmente a un EventEmitter? ¿Cómo debo usarlo?

Eric Martinez avatar Mar 18 '16 12:03 Eric Martinez
Aceptado

TL;DR :

No, no se suscriba manualmente a ellos, no los utilice en servicios. Úselos como se muestra en la documentación solo para emitir eventos en componentes. No derrotes la abstracción de angular.

Respuesta:

No, no debes suscribirte manualmente.

EventEmitter es una abstracción angular2 y su único propósito es emitir eventos en componentes. Citando un comentario de Rob Wormald

[...] EventEmitter es realmente una abstracción angular y debe usarse prácticamente solo para emitir eventos personalizados en componentes. De lo contrario, utilice Rx como si fuera cualquier otra biblioteca.

Esto se indica muy claramente en la documentación de EventEmitter.

Uso por directivas y componentes para emitir eventos personalizados.

¿Qué hay de malo en usarlo?

Angular2 nunca nos garantizará que EventEmitter seguirá siendo un Observable. Eso significa refactorizar nuestro código si cambia. La única API a la que debemos acceder es su emit()método. Nunca debemos suscribirnos manualmente a un EventEmitter.

Todo lo expuesto anteriormente queda más claro en este comentario de Ward Bell (se recomienda leer el artículo y la respuesta a ese comentario). Citando como referencia

¡NO cuente con que EventEmitter siga siendo un Observable!

¡NO cuente con que esos operadores Observables estén allí en el futuro!

Estos quedarán obsoletos pronto y probablemente se eliminarán antes de su lanzamiento.

Utilice EventEmitter solo para el enlace de eventos entre un componente secundario y uno principal. No te suscribas. No llame a ninguno de esos métodos. solo llamaeve.emit()

Su comentario está en línea con el comentario de Rob hace mucho tiempo.

Entonces, ¿cómo utilizarlo correctamente?

Simplemente utilícelo para emitir eventos desde su componente. Eche un vistazo al siguiente ejemplo.

@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!
    }
}

¿Cómo no usarlo?

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

Detente ahí... ya estás equivocado...

Con suerte, estos dos ejemplos simples aclararán el uso adecuado de EventEmitter.

Eric Martinez avatar Mar 18 '2016 05:03 Eric Martinez

Sí, adelante y úsalo.

EventEmitteres un tipo público y documentado en la API final de Angular Core. ObservableEs irrelevante si se basa o no en ; Si está documentado emity subscribelos métodos se adaptan a lo que necesita, continúe y utilícelo.

Como también se indica en los documentos:

Utiliza Rx.Observable pero proporciona un adaptador para que funcione como se especifica aquí: https://github.com/jhusain/observable-spec

Una vez que esté disponible una implementación de referencia de la especificación, cámbiela.

Entonces querían un Observableobjeto similar que se comportara de cierta manera, lo implementaron y lo hicieron público. Si fuera simplemente una abstracción angular interna que no debería usarse, no la habrían hecho pública.

Hay muchas ocasiones en las que resulta útil tener un emisor que envíe eventos de un tipo específico. Si ese es su caso de uso, hágalo. Si/cuando esté disponible una implementación de referencia de la especificación a la que se vinculan, debería ser un reemplazo directo, al igual que con cualquier otro polyfill.

Solo asegúrese de que el generador que pasa a la subscribe()función siga las especificaciones vinculadas. Se garantiza que el objeto devuelto tendrá un unsubscribemétodo al que se debe llamar para liberar cualquier referencia al generador (este es actualmente un objeto RxJsSubscription , pero de hecho es un detalle de implementación del que no se debe depender).

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();
    }
}

Todas las predicciones pesimistas fuertemente redactadas parecen surgir de un solo comentario de Stack Overflow de un solo desarrollador en una versión preliminar de Angular 2.

Tobias J avatar Nov 07 '2017 20:11 Tobias J

Cuando desee tener interacción entre componentes, necesitará saber qué son @Input, @Output, EventEmitter y Subjects.

Si la relación entre componentes es padre-hijo o viceversa, usamos @input y @output con emisor de eventos.

@output emite un evento y debes emitirlo utilizando el emisor de eventos.

Si no se trata de una relación entre padre e hijo... entonces debe utilizar sujetos o mediante un servicio común.

Akhil avatar Apr 27 '2019 10:04 Akhil

No hay: nono y no: sísi. La verdad está en el medio y no hay motivos para asustarse por la próxima versión de Angular.

Desde un punto de vista lógico, si tiene un componente y desea informar a otros componentes que algo sucede, se debe activar un evento y esto se puede hacer de cualquier manera que usted (desarrollador) crea que se debe hacer. No veo la razón por la cual no usarlo y no veo la razón por la cual usarlo a toda costa. Además, el nombre EventEmitter me sugiere que está sucediendo un evento. Normalmente lo uso para eventos importantes que suceden en el Componente. Creo el Servicio pero creo el archivo de Servicio dentro de la Carpeta de Componentes. Entonces mi archivo de Servicio se convierte en una especie de Administrador de Eventos o una Interfaz de Eventos, de modo que puedo determinar de un vistazo a qué evento puedo suscribirme en el componente actual.

Lo sé... Tal vez soy un desarrollador un poco anticuado. Pero esto no es parte del patrón de desarrollo impulsado por eventos, es parte de las decisiones de arquitectura de software de su proyecto particular.

Algunos otros pueden pensar que usar Observables directamente es genial. En ese caso, continúe directamente con Observables. No eres un asesino en serie haciendo esto. A menos que seas un desarrollador psicópata, hasta ahora el programa funciona, hazlo.

Claudio Ferraro avatar Jun 06 '2019 11:06 Claudio Ferraro