Qual é o uso adequado de um EventEmitter?

224

Eu li perguntas como o Access EventEmitter Service dentro do CustomHttp, onde o usuário usa EventEmitter em seu serviço, mas foi sugerido neste comentário para não usá-lo e, em vez disso, usar Observables diretamente em seus serviços.

Eu também li essa pergunta em que a solução sugere passar o EventEmitter para a criança e assinar.

Minha pergunta então é: Devo ou não devo me inscrever manualmente em um EventEmitter? Como devo usá-lo?

Eric Martinez
fonte
2
Possível duplicata da delegação: EventEmitter ou Observable em Angular2
Günter Zöchbauer 18/16
2
Boa resposta de Mark, como sempre, mas na verdade ele não explica por que eu expliquei. Não sou contra fechar, mas quero a opinião dele primeiro. @MarkRajcok pensamentos?
Eric Martinez
Eu gostaria de manter isso aberto (e tenho certeza de que apontarei as pessoas para cá - acabei de editar minha outra resposta para apontar aqui!). Sua resposta tem uma boa quantidade de informações adicionais. Eu quero dois títulos de perguntas, no entanto ... o outro é "Qual é o uso adequado de um EventEmitter?"
Mark Rajcok
@MarkRajcok eu gosto desse título, mas ele não se encaixa na resposta atual, por isso vou atualizá-lo mais tarde, adicionar exemplos de como usá-lo e como não fazê-lo, para que faça mais sentido. Obrigado por seu feedback :)
Eric Martinez
@ MarkRajcok editado como sugerido (y), (copie e cole o título sugerido, todos os créditos para você).
Eric Martinez

Respostas:

342

TL; DR :

Não, não se inscreva manualmente, não os use nos serviços. Use-os conforme mostrado na documentação apenas para emitir eventos nos componentes. Não derrote a abstração da angular.

Responda:

Não, você não deve se inscrever manualmente.

EventEmitter é uma abstração angular2 e seu único objetivo é emitir eventos nos componentes. Citando um comentário de Rob Wormald

[...] EventEmitter é realmente uma abstração Angular e deve ser usado praticamente apenas para emitir eventos personalizados nos componentes. Caso contrário, use Rx como se fosse qualquer outra biblioteca.

Isto é afirmado de forma clara na documentação do EventEmitter.

Use por diretivas e componentes para emitir eventos personalizados.

O que há de errado em usá-lo?

A Angular2 nunca nos garantirá que o EventEmitter continuará sendo um Observável. Isso significa refatorar nosso código se ele mudar. A única API que devemos acessar é seu emit()método. Nunca devemos assinar manualmente um EventEmitter.

Tudo o que foi dito acima é mais claro no comentário de Ward Bell (recomendado para ler o artigo e a resposta a esse comentário). Citando para referência

NÃO conte com o EventEmitter continuando sendo um Observável!

NÃO conte com esses operadores observáveis ​​no futuro!

Estes serão descontinuados em breve e provavelmente serão removidos antes do lançamento.

Use EventEmitter apenas para associação de eventos entre um componente filho e pai. Não assine. Não chame nenhum desses métodos. Ligar apenaseve.emit()

Seu comentário está alinhado com o comentário de Rob há muito tempo.

Então, como usá-lo corretamente?

Basta usá-lo para emitir eventos do seu componente. Veja o exemplo a seguir.

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

Como não usá-lo?

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

Pare aí ... você já está errado ...

Esperamos que esses dois exemplos simples esclareçam o uso adequado do EventEmitter.

Eric Martinez
fonte
1
O que você quer dizer com: directives : [Child]na definição de Componente? Isso não parece compilar, e não consigo encontrá-lo descrito na documentação do Angular2.
Themathmagician #
1
@ Eric: A maneira de não usá-lo no seu exemplo é muito óbvia, por que precisamos do decorador '@Output' em um serviço?
precisa saber é o seguinte
1
Depois de um pouco de pesquisa, descobri aqui que a directivespalavra-chave foi preterida. Utilizar a declarationspalavra-chave em @NgModulecomo indicado aqui ou aqui
cjsimon
5
Algum comentário sobre a resposta mais recente de Toby? Eu acho que a resposta dele deve ser a aceita hoje em dia.
Arjan #
7
@ Eric Quando você escreveu esta resposta, escreveu: 'Isso será preterido em breve e provavelmente removido antes do lançamento', citando Ward Bell. Mas isso foi afirmado há 2 anos e agora temos angular6. Esta declaração ainda se aplica agora? Continuo vendo no documento oficial que o EventEmitter ainda possui o método subscribe (), então acho que se o Google quisesse parar de basear o EE em assuntos de Rxjs, ele já o faria. Então você acha que sua resposta original ainda se ajusta bem ao estado atual do Angular?
Nad G
100

Sim, vá em frente e use-o.

EventEmitteré um tipo público e documentado na API final do Angular Core. Se é ou não baseado Observableé irrelevante; se os métodos emite os documentos estão de subscribeacordo com o que você precisa, vá em frente e use-o.

Como também indicado nos documentos:

Usa Rx.Observable, mas fornece um adaptador para fazê-lo funcionar conforme especificado aqui: https://github.com/jhusain/observable-spec

Quando uma implementação de referência da especificação estiver disponível, mude para ela.

Então, eles queriam um Observableobjeto semelhante que se comportasse de uma certa maneira, eles o implementaram e o tornaram público. Se fosse apenas uma abstração angular interna que não deveria ser usada, eles não a tornariam pública.

Muitas vezes é útil ter um emissor que envia eventos de um tipo específico. Se esse for o seu caso de uso, vá em frente. Se / quando estiver disponível uma implementação de referência das especificações às quais eles vinculam, ela deve ser uma substituição imediata, como em qualquer outro polyfill.

Apenas certifique-se de que o gerador que você passa para a subscribe()função siga as especificações vinculadas. É garantido que o objeto retornado tenha um unsubscribemétodo que deve ser chamado para liberar qualquer referência ao gerador (atualmente esse é um objeto RxJs,Subscription mas esse é realmente um detalhe de implementação do qual não se deve confiar ).

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 as previsões sombrias de desgraça e melancolia parecem resultar de um único comentário do Stack Overflow de um único desenvolvedor em uma versão de pré-lançamento do Angular 2.

Tobias J
fonte
2
Isso parece razoável - mais alguém quer avaliar isso? afinal, é um método público para um emissor de eventos?
21418 Shawson
Ok, é público, então estamos livres para usá-lo. Mas há algum motivo prático para usar EventEmitter sobre Observable neste exemplo?
Botis
6
Agora estamos no Angular v6 e o ​​EventEmmiter não foi preterido ou removido, então eu diria que é seguro usá-lo. No entanto, vejo benefícios em aprender a usar o Observables do RxJS.
21818 David Meza #
Eu vejo isso como "se você estiver usando o EventEmitter fora do @Output, não será necessário se apressar para alterá-lo para outra coisa, pois a API é um ATM estável"; se você tiver tempo ou a API quebrar, precisará alterá-la (mas lembre-se de que, para angular, alterar uma API pública estável (emitir e assinar) não é comum). Também manter o api pública, não métodos não acesso de Assunto ou observável que não estão definidos na EventEmitter para ficar no lado seguro
acidghost
1
A suposição de que algo é seguro de usar por causa de "não foi removido do Angular" ou "bem documentado" está errada, assim como a política nono proposta acima. Você cria um projeto não pelo motivo de futuras versões do angular. Existem muitas plataformas não mantidas lá fora, ainda trabalhando na web. A versão da estrutura não torna os desenvolvedores que estavam trabalhando nessas plataformas menos desenvolvedores ou desenvolvedores da categoria B.
Claudio Ferraro
4

Quando você deseja ter uma interação entre componentes, precisa saber o que são @Input, @Output, EventEmitter e Subject.

Se a relação entre os componentes é pai-filho ou vice-versa, usamos @input & @output com o emissor do evento.

@output emite um evento e você precisa emitir usando o emissor de eventos.

Se não for um relacionamento entre pais e filhos, é preciso usar assuntos ou através de um serviço comum.

Akhil
fonte
0

Não há: nono e não: yesyes. A verdade está no meio E não há motivos para ter medo por causa da próxima versão do Angular.

Do ponto de vista lógico, se você tem um componente e deseja informar outros componentes que algo acontece, um evento deve ser disparado e isso pode ser feito da maneira que você (desenvolvedor) pensa que deve ser feito. Não vejo o motivo para não usá-lo e não vejo o motivo para usá-lo a todo custo. Também o nome EventEmitter me sugere um evento acontecendo. Eu costumo usá-lo para eventos importantes que acontecem no componente. Crio o serviço, mas crio o arquivo de serviço dentro da pasta Component. Portanto, meu arquivo de serviço se torna uma espécie de gerenciador de eventos ou uma interface de eventos, para que eu possa descobrir rapidamente qual evento posso assinar no componente atual.

Eu sei .. Talvez eu seja um pouco um desenvolvedor antiquado. Mas isso não faz parte do padrão de desenvolvimento orientado a eventos, faz parte das decisões de arquitetura de software do seu projeto em particular.

Alguns outros caras podem pensar que usar o Observables diretamente é legal. Nesse caso, vá em frente diretamente com o Observables. Você não é um serial killer fazendo isso. A menos que você seja um desenvolvedor de psicopatas, até agora o Programa funciona, faça-o.

Claudio Ferraro
fonte