Qual è l'uso corretto di un EventEmitter?


224

Ho letto domande come Access EventEmitter Service all'interno di CustomHttp in cui l'utente utilizza EventEmitter nel suo servizio, ma in questo commento gli è stato suggerito di non usarlo e di utilizzare invece gli osservabili direttamente nei suoi servizi.

Ho anche letto questa domanda in cui la soluzione suggerisce di passare l'EventEmitter al figlio e di sottoscriverlo.

La mia domanda allora è: dovrei o non dovrei abbonarmi manualmente a un EventEmitter? Come dovrei usarlo?



2
Buona risposta di Mark, come al solito, ma in realtà non spiega perché l'ho spiegato. Non sono contrario a chiuderlo, ma voglio prima la sua opinione. Pensieri @MarkRajcok?
Eric Martinez,

Vorrei tenerlo aperto (e sono sicuro che indicherò le persone qui - ho appena modificato la mia altra risposta per indicare qui!). La tua risposta contiene molte informazioni aggiuntive. Voglio due titoli di domande però ... l'altro è "Qual è l'uso corretto di un EventEmitter?"
Mark Rajcok,

@MarkRajcok mi piace quel titolo ma non si adatterebbe con la risposta attuale, quindi mi assicurerò di aggiornarlo in seguito, aggiungere esempi su come usarlo e come non farlo, quindi ha più senso. Grazie per il tuo feedback :)
Eric Martinez,

@MarkRajcok modificato come suggerito (y), (copia e incolla il titolo suggerito, tutti i crediti per te).
Eric Martinez,

Risposte:


342

TL; DR :

No, non iscriverti manualmente a loro, non utilizzarli nei servizi. Usali come mostrato nella documentazione solo per emettere eventi nei componenti. Non sconfiggere l'astrazione di Angular.

Risposta:

No, non dovresti iscriverti manualmente ad esso.

EventEmitter è un'astrazione angolare2 e il suo unico scopo è quello di emettere eventi nei componenti. Citando un commento di Rob Wormald

[...] EventEmitter è in realtà un'astrazione angolare e dovrebbe essere usata praticamente solo per emettere eventi personalizzati nei componenti. Altrimenti, usa Rx come se fosse qualsiasi altra libreria.

Questo è affermato chiaramente nella documentazione di EventEmitter.

Utilizzare da direttive e componenti per emettere eventi personalizzati.

Cosa c'è di sbagliato nell'usarlo?

Angular2 non ci garantirà mai che EventEmitter continuerà a essere osservabile. Quindi questo significa refactoring del nostro codice se cambia. L'unica API a cui dobbiamo accedere è il suo emit()metodo. Non dovremmo mai abbonarci manualmente a un EventEmitter.

Tutto quanto detto sopra è più chiaro nel commento di Ward Bell (si consiglia di leggere l'articolo e la risposta a quel commento). Citando per riferimento

NON contare su EventEmitter che continua a essere osservabile!

NON contare su quegli operatori osservabili presenti in futuro!

Questi saranno presto deprecati e probabilmente rimossi prima del rilascio.

Utilizzare EventEmitter solo per l'associazione di eventi tra un componente figlio e genitore. Non abbonarti. Non chiamare nessuno di questi metodi. Chiama soloeve.emit()

Il suo commento è in linea con quello di Rob molto tempo fa.

Quindi, come usarlo correttamente?

Usalo semplicemente per emettere eventi dal tuo componente. Dai un'occhiata al seguente esempio.

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

Come non usarlo?

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

Smetti proprio lì ... ti sbagli già ...

Speriamo che questi due semplici esempi chiariscano il corretto utilizzo di EventEmitter.


1
Cosa intendi con: directives : [Child]nella definizione del componente? Questo non sembra compilare, e non riesco a trovarlo descritto nella documentazione di Angular2.
themathmagician

1
@Eric: Il modo di non usarlo nel tuo esempio è ovviamente evidente, perché abbiamo bisogno del decoratore "@Output" in un servizio?
trungk18,

1
@themathmagician Dopo un po 'di ricerche, ho scoperto qui che la directivesparola chiave è diventata obsoleta. Usa la declarationsparola chiave @NgModulecome indicato qui o qui
cjsimon

5
Qualche commento sulla risposta più recente di Toby? Immagino che la sua risposta dovrebbe essere quella accettata al giorno d'oggi.
Arjan,

7
@Eric Quando hai scritto questa risposta hai scritto: "Questi saranno presto disapprovati e probabilmente rimossi prima del rilascio", citando Ward Bell. Ma questo è stato affermato 2 anni fa e ora abbiamo angular6. Questa affermazione si applica ancora adesso? Continuo a vedere nel documento ufficiale che EventEmitter ha ancora il metodo iscriviti (), quindi penso che se Google volesse smettere di basare EE su argomenti Rxjs lo avrebbero già fatto. Quindi pensi che la tua risposta originale si adatti ancora bene allo stato attuale di Angular?
Nad G,

100

Sì, vai avanti e usalo.

EventEmitterè un tipo pubblico e documentato nell'API Angular Core finale. Che si basi o meno Observableè irrilevante; se è documentato emite i subscribemetodi sono adatti a ciò di cui hai bisogno, vai avanti e usalo.

Come indicato anche nei documenti:

Utilizza Rx.Observable ma fornisce un adattatore per farlo funzionare come specificato qui: https://github.com/jhusain/observable-spec

Una volta disponibile un'implementazione di riferimento della specifica, passa ad essa.

Quindi volevano un Observableoggetto simile che si comportava in un certo modo, lo implementavano e lo rendevano pubblico. Se fosse stata semplicemente un'astrazione angolare interna che non avrebbe dovuto essere utilizzata, non l'avrebbero resa pubblica.

Ci sono molte volte in cui è utile avere un emettitore che invia eventi di un tipo specifico. Se questo è il tuo caso d'uso, provalo. Se / quando è disponibile un'implementazione di riferimento delle specifiche a cui si collegano, dovrebbe essere una sostituzione drop-in, proprio come con qualsiasi altro polyfill.

Assicurati solo che il generatore che passi alla subscribe()funzione segua le specifiche collegate. L'oggetto restituito è garantito per avere un unsubscribemetodo che dovrebbe essere chiamato per liberare qualsiasi riferimento al generatore (questo è attualmente un oggetto RxJsSubscription ma che in effetti è un dettaglio di implementazione che non dovrebbe dipendere da).

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

Tutte le previsioni di condanna e oscurità formulate con parole forti sembrano derivare da un singolo commento di Stack Overflow di un singolo sviluppatore su una versione pre-release di Angular 2.


2
Sembra ragionevole, qualcun altro vuole pesare su questo? iscriversi è un metodo pubblico su un emettitore di eventi dopo tutto?
Shawson,

Ok, è pubblico, quindi siamo liberi di usarlo. Ma c'è qualche motivo pratico per usare EventEmitter su Observable in questo esempio?
Botis,

6
Siamo ora su Angular v6 ed EventEmmiter non è stato deprecato o rimosso, quindi direi che è sicuro da usare. Tuttavia, vedo benefici nell'apprendere come usare gli osservabili da RxJS.
David Meza,

Lo vedo come "se stai usando EventEmitter al di fuori di @Output, non c'è bisogno di affrettarti a cambiarlo in qualcos'altro in quanto l'API è ATM stabile"; se hai tempo o le pause dell'API dovrai cambiarlo (ma tieni presente che per l'angolare cambiare un'API pubblica stabile (emetti e iscriviti) non è comune). Attenersi anche alle API pubbliche, non accedere a metodi di Soggetto o Osservabile che non sono definiti in EventEmitter per rimanere sul lato più sicuro
acidghost

1
L'ipotesi che qualcosa sia sicuro da usare a causa di "non rimosso dall'angolare" o "ben documentato" è errata, così come la politica di Nono proposta sopra. Si crea un progetto non per la ragione delle versioni future di angolare. Ci sono molte piattaforme non gestite là fuori che funzionano ancora sul web. La versione del framework non rende gli sviluppatori che stavano lavorando su quelle piattaforme meno sviluppatori o sviluppatori della categoria B.
Claudio Ferraro,

4

Quando si desidera avere un'interazione tra componenti, è necessario sapere cosa sono @Input, @Output, EventEmitter e Subject.

Se la relazione tra i componenti è padre-figlio o viceversa utilizziamo @input e @output con l'emettitore di eventi.

@output emette un evento ed è necessario emetterlo utilizzando l'emettitore di eventi.

Se non si tratta di relazione figlio-genitore ... allora devi usare soggetti o attraverso un servizio comune.


0

Non c'è: nono e no: sì. La verità è nel mezzo e non ci sono motivi per essere spaventati a causa della prossima versione di Angular.

Da un punto di vista logico, se si dispone di un componente e si desidera informare altri componenti che qualcosa accade, un evento dovrebbe essere generato e ciò può essere fatto in qualsiasi modo tu (sviluppatore) pensi che dovrebbe essere fatto. Non vedo il motivo per cui non utilizzarlo e non vedo il motivo per cui utilizzarlo a tutti i costi. Anche il nome EventEmitter mi suggerisce che sta accadendo un evento. Di solito lo uso per eventi importanti che accadono nel Componente. Creo il servizio ma creo il file di servizio all'interno della cartella dei componenti. Quindi il mio file di servizio diventa una sorta di Event Manager o un'interfaccia di evento, così posso capire a colpo d'occhio a quale evento posso iscrivermi sul componente corrente.

Lo so ... forse sono un po 'un vecchio sviluppatore. Ma questo non fa parte del modello di sviluppo Event Driven, fa parte delle decisioni sull'architettura software del tuo particolare progetto.

Alcuni altri ragazzi potrebbero pensare che usare direttamente gli osservabili sia bello. In tal caso, procedi direttamente con Observables. Non sei un serial killer che lo fa. A meno che tu non sia uno sviluppatore di psicopatici, finora il programma funziona, fallo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.