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

224

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

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

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

Eric Martinez
fuente
2
Posible duplicado de la delegación: EventEmitter u Observable en Angular2
Günter Zöchbauer
2
Buena respuesta de Mark, como siempre, pero en realidad no explica por qué lo expliqué. No estoy en contra de cerrarlo, pero primero quiero su opinión. @MarkRajcok pensamientos?
Eric Martinez
Me gustaría mantener esto abierto (y estoy seguro de que señalaré a las personas aquí, ¡acabo de editar mi otra respuesta para señalar aquí!). Su respuesta tiene una buena cantidad de información adicional. Sin embargo, quiero dos títulos de preguntas ... el otro es "¿Cuál es el uso adecuado de un EventEmitter?"
Mark Rajcok
@MarkRajcok Me gusta ese título, pero no encaja con la respuesta actual, así que me aseguraré de actualizarlo más tarde, agregar ejemplos de cómo usarlo y cómo no hacerlo para que tenga más sentido. Gracias por sus comentarios :)
Eric Martinez
@MarkRajcok editado como se sugiere (y), (copie y pegue el título sugerido, todos los créditos para usted).
Eric Martinez

Respuestas:

342

TL; DR :

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

Responder:

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, solo use Rx como si fuera cualquier otra biblioteca.

Esto se afirma realmente claro 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 continuará 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 mencionado anteriormente es más claro en el comentario de Ward Bell (recomendado para leer el artículo y la respuesta a ese comentario). Citando para referencia

¡NO cuente con que EventEmitter continúe siendo un Observable!

¡NO cuente con que los operadores Observables estarán allí en el futuro!

Estos serán obsoletos pronto y probablemente eliminados antes del lanzamiento.

Use EventEmitter solo para el enlace de eventos entre un componente secundario y uno primario. No te suscribas a él. No llame a ninguno de esos métodos. Solo llamareve.emit()

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

Entonces, ¿cómo usarlo 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 ...

Esperemos que estos dos ejemplos simples aclaren el uso adecuado de EventEmitter.

Eric Martinez
fuente
1
¿Qué quiere decir con: directives : [Child]en la definición de componente? Esto no parece compilarse, y no puedo encontrarlo descrito en la documentación de Angular2.
themathmagician
1
@Eric: El cómo no usarlo en su ejemplo es muy obvio, ¿por qué necesitamos un decorador '@Output' en un servicio?
trungk18
1
@themathmagician Después de un poco de investigación, encontré aquí que la directivespalabra clave ha quedado en desuso. Use la declarationspalabra clave @NgModulecomo se indica aquí o aquí
cjsimon
55
¿Algún comentario sobre la respuesta más reciente de Toby? Supongo que su respuesta debería ser la aceptada hoy en día.
Arjan
77
@Eric Cuando escribiste esta respuesta, escribiste: 'Estos serán desaprobados pronto y probablemente eliminados antes del lanzamiento', citando a Ward Bell. Pero esto se afirmó hace 2 años y ahora tenemos angular6. ¿Esta declaración se aplica todavía ahora? Sigo viendo en el documento oficial que EventEmitter todavía tiene el método subscribe (), por lo que creo que si Google quisiera dejar de basar EE en temas de Rxjs, ya lo habrían hecho. Entonces, ¿crees que tu respuesta original todavía se ajusta bien al estado actual de Angular?
Nad G
100

Sí, adelante y úsalo.

EventEmitteres un tipo público y documentado en la API final de Angular Core. Si se basa o no Observablees irrelevante; si está documentado emitysubscribe métodos se ajustan a lo que necesita, continúe y úselo.

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 una implementación de referencia de la especificación esté disponible, cámbiela.

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

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

Solo asegúrese de que el generador que pase a la subscribe()función siga las especificaciones vinculadas. Se garantiza que el objeto devuelto tiene un unsubscribemétodo que debería llamarse para liberar cualquier referencia al generador (actualmente es 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 y pesimistas fuertemente redactadas parecen provenir de un solo comentario de Stack Overflow de un solo desarrollador en una versión preliminar de Angular 2.

Tobias J
fuente
2
Esto suena razonable, ¿alguien más quiere opinar sobre esto? ¿Suscribirse es un método público en un emisor de eventos después de todo?
Shawson
Ok, es público, así que somos libres de usarlo. Pero, ¿hay alguna razón práctica para usar EventEmitter sobre Observable en este ejemplo?
Botis
66
Ahora estamos en Angular v6 y EventEmmiter no fue desaprobado o eliminado, por lo que diría que es seguro de usar. Sin embargo, veo beneficios en aprender a usar Observables de RxJS.
David Meza
Lo veo como "si está utilizando EventEmitter fuera de @Output, no es necesario apresurarse a cambiarlo a otra cosa, ya que la API es un cajero automático estable"; si tiene tiempo o la api se rompe, tendrá que cambiarla (pero tenga en cuenta que para que angular cambie una api pública estable (emitir y suscribirse) no es común). También se adhieren a la API pública, no acceda a métodos de sujeto u observable que no estén definidos en EventEmitter para mantenerse en el lado más seguro
acidghost
1
La suposición de que algo es seguro de usar debido a que "no ha sido eliminado de Angular" o "bien documentado" es errónea, así como también la política de nono propuesta anteriormente. Crea un proyecto no por el motivo de futuras versiones de angular. Hay muchas plataformas no mantenidas fuera de allí que todavía funcionan en la web. La versión del marco no hace que los desarrolladores que estaban trabajando en esas plataformas sean menos desarrolladores o desarrolladores de categoría B.
Claudio Ferraro
4

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

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

@output emite un evento y debe emitir utilizando el emisor de eventos.

Si no se trata de una relación padre-hijo ... entonces debe usar temas o mediante un servicio común.

Akhil
fuente
0

No hay: nono y no: sí, sí. La verdad está en el medio Y no hay razones para tener miedo debido a la próxima versión de Angular.

Desde un punto de vista lógico, si tiene un componente y desea informar a otros componentes de que algo sucede, se debe activar un evento y esto se puede hacer de la forma que usted (desarrollador) piense que debería hacerse. No veo la razón por la que no lo uso y no veo la razón por la que lo uso a toda costa. También el nombre de EventEmitter me sugiere que suceda un evento. Usualmente 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. Por lo tanto, mi archivo de Servicio se convierte en una especie de Administrador de eventos o una Interfaz de eventos, de modo que puedo averiguar a simple vista 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 Event Driven, es parte de las decisiones de arquitectura de software de su proyecto en particular.

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

Claudio Ferraro
fuente