web-dev-qa-db-fra.com

Quelle est la bonne utilisation d'un EventEmitter?

J'ai lu des questions comme Access EventEmitter Service à l'intérieur de CustomHttp où l'utilisateur utilise EventEmitter dans son service, mais il a été suggéré dans ce commentaire de ne pas l'utiliser et d'utiliser plutôt Observables directement dans ses services.

J'ai aussi lu ceci question où la solution suggère de transmettre EventEmitter à l'enfant et de s'y abonner.

Ma question est alors la suivante: devrais-je ou ne devrais-je pas souscrire manuellement à un EventEmitter? Comment devrais-je l'utiliser?

188
Eric Martinez

Non, vous ne devriez pas vous y abonner manuellement.

EventEmitter est une abstraction angular2 et son seul but est d’émettre des événements dans des composants. Citer un commentaire de Rob Wormald

[...] EventEmitter est vraiment une abstraction Angular et ne devrait être utilisé que pour l’émission d’événements personnalisés dans des composants. Sinon, utilisez simplement Rx comme s'il s'agissait d'une autre bibliothèque.

Ceci est indiqué très clairement dans la documentation de EventEmitter.

Utilisez des directives et des composants pour émettre des événements personnalisés.

Quel est le problème à propos de l'utiliser?

Angular2 ne nous garantira jamais qu'EventEmitter continuera d'être un observable. Donc, cela signifie refactoriser notre code s'il change. La seule API à laquelle nous devons accéder est sa méthode emit(). Nous ne devrions jamais souscrire manuellement à un EventEmitter.

Tous les énoncés ci-dessus sont plus clairs dans le commentaire commentaire de ce Ward Bell (il est recommandé de lire l'article et le réponse à ce commentaire). Citant pour référence

Ne comptez pas sur EventEmitter pour continuer à être un observable!

Ne comptez pas sur la présence future d’opérateurs observables!

Celles-ci seront bientôt obsolètes et probablement supprimées avant la publication.

Utilisez EventEmitter uniquement pour la liaison d'événement entre un composant enfant et un composant parent. Ne vous y abonnez pas. N'appelez aucune de ces méthodes. Appelez seulement eve.emit()

Son commentaire est conforme à celui de Rob il y a longtemps.

Alors, comment l'utiliser correctement?

Utilisez-le simplement pour émettre des événements à partir de votre composant. Jetez un oeil à l'exemple suivant.

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

Comment ne pas l'utiliser?

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

Arrêtez-vous là ... vous vous trompez déjà ...

Espérons que ces deux exemples simples clarifieront l'utilisation correcte de EventEmitter.

TL; DR réponse:

Non, ne vous y abonnez pas manuellement, ne les utilisez pas dans des services. Utilisez-les comme indiqué dans la documentation uniquement pour émettre des événements dans des composants. Ne pas vaincre l'abstraction angulaire.

302
Eric Martinez

Oui, allez-y et utilisez-le.

EventEmitter est un public, type documenté dans l'API de base Angular finale. Que ce soit ou non basé sur Observable est sans importance; si ses méthodes documentées emit et subscribe conviennent à vos besoins, utilisez-les.

Comme indiqué également dans la documentation:

Utilise Rx.Observable mais fournit un adaptateur pour que cela fonctionne comme spécifié ici: https://github.com/jhusain/observable-spec

Une fois qu'une implémentation de référence de la spécification est disponible, basculez-y.

Alors ils voulaient un objet Observable comme qui se comportait d'une certaine manière, ils l'ont mis en œuvre et rendu public. S'il s'agissait simplement d'une abstraction interne Angular qui ne devrait pas être utilisée, ils ne l'auraient pas rendue publique.

Il est souvent utile d'avoir un émetteur qui envoie des événements d'un type spécifique. Si c'est votre cas d'utilisation, allez-y. Si/quand une implémentation de référence de la spécification à laquelle ils sont liés est disponible, il devrait être un remplacement immédiat, comme avec tout autre polyfill.

Assurez-vous simplement que le générateur que vous passez à la fonction subscribe() suit la spécification liée. Il est garanti que l'objet retourné a une méthode unsubscribe qui devrait être appelée pour libérer toutes les références au générateur (il s'agit actuellement d'un objet RxJs Subscription , mais il s'agit bien d'une implémentation. détail sur lequel il ne faut pas compter).

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

Toutes les prédictions fortement libellées de Doom et de morosité semblent provenir d'un seul commentaire Stack Overflow émis par un seul développeur sur une version préliminaire de Angular 2.

84
Toby J

Lorsque vous souhaitez avoir une interaction entre composants, vous devez savoir quels sont @Input, @Output, EventEmitter et Subjects.

Si la relation entre les composants est parent-enfant ou inversement, nous utilisons @input & @output avec event emitter.

@output émet un événement et vous devez émettre à l'aide de event emitter.

S'il ne s'agit pas d'une relation parent-enfant, vous devez utiliser des sujets ou utiliser un service commun.

3
Akhil

D'un point de vue assez logique. Si vous avez un composant et que vous souhaitez informer d'autres composants qu'il se passe quelque chose, un événement doit être déclenché. Je ne vois pas la raison pour laquelle ne pas l'utiliser. De plus, le nom de EventEmitter me suggère un événement. Je l'utilise généralement pour des événements importants se produisant dans la portée du composant. Je crée le service mais je crée le fichier de service dans le dossier des composants. Ainsi, mon fichier de service devient une sorte de gestionnaire d’événements ou d’interface d’événement, ce qui me permet de déterminer immédiatement à quel événement je peux souscrire pour le composant actuel.

Je sais .. Peut-être que je suis un peu un vieux développeur passionné.

Mais cela s'appelle un modèle de développement: Event Driven.

D'autres peuvent penser que les Observables sont cool. Dans ce cas, continuez avec Observables. Vous n'êtes pas un meurtrier qui fait cela jusqu'ici le programme fonctionne le faire.

Il y a non: nono et non: oui.

0
Claudio Ferraro