Apa penggunaan yang tepat dari EventEmitter?

224

Saya telah membaca pertanyaan seperti Layanan Access EventEmitter di dalam CustomHttp di mana pengguna menggunakan EventEmitter dalam layanannya, tetapi dia disarankan dalam komentar ini untuk tidak menggunakannya dan untuk menggunakannya sebagai pengamat langsung dalam layanannya.

Saya juga membaca pertanyaan ini di mana solusinya menyarankan untuk meneruskan EventEmitter ke anak dan berlangganan.

Pertanyaan saya kemudian adalah: Haruskah saya, atau saya tidak boleh berlangganan secara manual ke EventEmitter? Bagaimana saya harus menggunakannya?

Eric Martinez
sumber
2
Kemungkinan rangkap Delegasi: EventEmitter atau Observable in Angular2
Günter Zöchbauer
2
Jawaban yang bagus dari Mark, seperti biasa, tetapi sebenarnya dia tidak menjelaskan mengapa saya menjelaskan. Saya tidak menentang untuk menutupnya, tetapi saya menginginkan pendapatnya terlebih dahulu. Pikiran @RarkRajcok?
Eric Martinez
Saya ingin tetap terbuka (dan saya yakin saya akan menunjukkan orang di sini - saya hanya mengedit jawaban saya yang lain untuk menunjuk di sini!). Jawaban Anda memiliki sedikit informasi tambahan. Saya ingin dua judul pertanyaan ... yang lain adalah "Apa penggunaan yang tepat dari EventEmitter?"
Mark Rajcok
@ MarkRajcok saya suka judul itu tetapi tidak cocok dengan jawaban saat ini, jadi saya akan pastikan untuk memperbaruinya nanti, tambahkan contoh cara menggunakannya dan bagaimana tidak jadi lebih masuk akal. Terima kasih atas tanggapan Anda :)
Eric Martinez
@MarkRajcok diedit seperti yang disarankan (y), (salin & tempel judul yang disarankan, semua kredit untuk Anda).
Eric Martinez

Jawaban:

342

TL; DR :

Tidak, jangan berlangganan secara manual kepada mereka, jangan menggunakannya dalam layanan. Gunakan mereka seperti yang ditunjukkan dalam dokumentasi hanya untuk memancarkan peristiwa dalam komponen. Jangan mengalahkan abstraksi sudut.

Menjawab:

Tidak, Anda tidak harus berlangganan secara manual.

EventEmitter adalah abstraksi angular2 dan satu-satunya tujuannya adalah untuk memancarkan peristiwa dalam komponen. Mengutip komentar dari Rob Wormald

[...] EventEmitter benar-benar abstraksi Angular, dan harus digunakan cukup banyak hanya untuk memancarkan Acara kustom dalam komponen. Kalau tidak, cukup gunakan Rx seolah-olah itu perpustakaan lain.

Ini dinyatakan sangat jelas dalam dokumentasi EventEmitter.

Gunakan dengan arahan dan komponen untuk memancarkan Acara kustom.

Apa yang salah dengan menggunakannya?

Angular2 tidak akan pernah menjamin kami bahwa EventEmitter akan terus menjadi Observable. Jadi itu berarti refactoring kode kita jika ada perubahan. Satu-satunya API yang harus kita akses adalah emit()metodenya. Kita tidak boleh berlangganan secara manual ke EventEmitter.

Semua yang dinyatakan di atas lebih jelas dalam komentar Ward Bell ini (disarankan untuk membaca artikel, dan jawaban untuk komentar itu). Mengutip untuk referensi

JANGAN mengandalkan EventEmitter yang terus menjadi Observable!

JANGAN mengandalkan operator yang bisa diamati itu di masa depan!

Ini akan segera ditinggalkan dan mungkin dihapus sebelum rilis.

Gunakan EventEmitter hanya untuk pengikatan acara antara komponen anak dan orang tua. Jangan berlangganan untuk itu. Jangan panggil metode tersebut. Hanya panggilaneve.emit()

Komentarnya sudah sesuai dengan komentar Rob sejak dulu.

Jadi, bagaimana cara menggunakannya dengan benar?

Cukup gunakan untuk memancarkan acara dari komponen Anda. Lihatlah contoh berikut.

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

Bagaimana tidak menggunakannya?

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

Berhenti di sana ... Anda sudah salah ...

Semoga dua contoh sederhana ini akan menjelaskan penggunaan yang tepat dari EventEmitter.

Eric Martinez
sumber
1
Apa yang Anda maksud dengan: directives : [Child]dalam definisi Komponen? Ini tampaknya tidak dapat dikompilasi, dan saya tidak dapat menemukannya dijelaskan dalam dokumentasi Angular2.
themathmagician
1
@ Eric: Cara tidak menggunakannya dalam contoh Anda sangat jelas, mengapa kita membutuhkan dekorator '@Output' dalam layanan?
trungk18
1
@themathmagician Setelah sedikit riset, saya menemukan di sini bahwa directiveskata kunci tersebut sudah tidak digunakan lagi. Gunakan declarationskata kunci @NgModuleseperti yang diarahkan di sini atau di sini
cjsimon
5
Ada komentar tentang jawaban Toby yang lebih baru? Saya kira jawabannya adalah jawaban yang diterima saat ini.
Arjan
7
@ Eric Ketika Anda menulis jawaban ini, Anda menulis: 'Ini akan segera ditinggalkan dan mungkin dihapus sebelum dirilis', mengutip Ward Bell. Tapi ini dinyatakan 2 tahun lalu dan sekarang kita memiliki angular6. Apakah pernyataan ini masih berlaku sekarang? Saya terus melihat dalam dokumen resmi bahwa EventEmitter masih memiliki metode berlangganan (), jadi saya berpikir bahwa jika Google ingin berhenti mendasarkan EE pada subjek Rxjs, mereka sudah akan melakukannya. Jadi menurut Anda apakah jawaban awal Anda masih cocok dengan keadaan Angular saat ini?
Nad G
100

Ya, silakan dan gunakan.

EventEmitteradalah tipe publik dan terdokumentasi dalam API Inti Sudut akhir. Apakah didasarkan atau tidak itu tidak Observablerelevan; jika didokumentasikan emitdan subscribemetode yang sesuai dengan apa yang Anda butuhkan, maka maju dan gunakan.

Seperti yang dinyatakan dalam dokumen:

Menggunakan Rx.Observable tetapi menyediakan adaptor untuk membuatnya berfungsi seperti yang ditentukan di sini: https://github.com/jhusain/observable-spec

Setelah implementasi referensi dari spesifikasi tersedia, beralihlah ke sana.

Jadi mereka menginginkan Observableobjek serupa yang berperilaku dengan cara tertentu, mereka mengimplementasikannya, dan mempublikasikannya. Jika itu hanya abstraksi sudut internal yang tidak boleh digunakan, mereka tidak akan dipublikasikan.

Ada banyak waktu ketika berguna untuk memiliki emitor yang mengirimkan peristiwa dari tipe tertentu. Jika itu kasus penggunaan Anda, lakukan. Jika / ketika implementasi referensi dari spec yang mereka tautkan tersedia, itu harus menjadi pengganti drop-in, seperti halnya dengan polyfill lainnya.

Pastikan saja generator yang Anda operasikan ke subscribe()fungsi mengikuti spesifikasi yang ditautkan. Objek yang dikembalikan dijamin memiliki unsubscribemetode yang harus dipanggil untuk membebaskan referensi ke generator (ini saat ini merupakan objek RxJsSubscription tetapi itu memang detail implementasi yang tidak boleh bergantung pada).

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

Semua prediksi azab dan kemuraman yang sangat kuat tampaknya berasal dari komentar Stack Overflow tunggal dari pengembang tunggal pada versi pra-rilis Angular 2.

Tobias J
sumber
2
Ini terdengar masuk akal - ada orang yang ingin mempertimbangkan ini? berlangganan adalah metode publik pada emitor acara?
Shawson
Oke, ini untuk umum, jadi kami bebas menggunakannya. Tetapi apakah ada alasan praktis untuk menggunakan EventEmitter over Observable dalam contoh ini?
Botis
6
Kami sekarang di Angular v6 dan EventEmmiter tidak ditinggalkan atau dihapus jadi saya akan mengatakan itu aman untuk digunakan. Namun, saya melihat manfaat untuk mempelajari cara menggunakan Observables dari RxJS.
David Meza
Saya melihatnya sebagai "jika Anda menggunakan EventEmitter di luar @Output, tidak perlu terburu-buru mengubahnya menjadi sesuatu yang lain karena apinya adalah ATM yang stabil"; jika Anda punya waktu atau api istirahat Anda harus mengubahnya (tetapi perlu diingat bahwa untuk sudut untuk mengubah api stabil publik (memancarkan dan berlangganan) tidak umum). Juga berpegang teguh pada api publik, jangan mengakses metode Subjek atau Dapat Diamati yang tidak didefinisikan dalam EventEmitter untuk tetap berada di sisi yang lebih aman
acidghost
1
Asumsi bahwa ada sesuatu yang aman untuk digunakan karena "tidak dihapus dari Angular" atau "terdokumentasi dengan baik" adalah salah dan kebijakan nono yang diusulkan di atas. Anda membuat proyek bukan karena versi sudut masa depan. Ada banyak platform yang tidak dijaga di luar sana yang masih berfungsi di web. Versi kerangka kerja ini tidak membuat pengembang yang bekerja pada platform tersebut lebih sedikit pengembang atau pengembang dari kategori B.
Claudio Ferraro
4

Saat Anda ingin memiliki interaksi lintas komponen, maka Anda perlu tahu apa itu @Input, @Output, EventEmitter, dan Subjek.

Jika hubungan antara komponen adalah orangtua-anak atau sebaliknya kita menggunakan @input & @output dengan event emitor ..

@output memancarkan suatu acara dan Anda harus memancarkannya menggunakan emitor acara.

Jika itu bukan hubungan anak orang tua .. maka Anda harus menggunakan subjek atau melalui layanan umum.

Akhil
sumber
0

Tidak ada: nono dan tidak: yesyes. Kebenarannya ada di tengah dan tidak ada alasan untuk takut karena versi Angular berikutnya.

Dari sudut pandang logis, jika Anda memiliki Komponen dan Anda ingin memberi tahu komponen lain bahwa sesuatu terjadi, suatu peristiwa harus dipecat dan ini dapat dilakukan dengan cara apa pun yang menurut Anda (pengembang) harus dilakukan. Saya tidak melihat alasan mengapa tidak menggunakannya dan saya tidak melihat alasan mengapa menggunakannya dengan cara apa pun. Juga nama EventEmitter menunjukkan kepada saya suatu peristiwa yang terjadi. Saya biasanya menggunakannya untuk acara penting yang terjadi di Komponen. Saya membuat Layanan tetapi membuat file Layanan di dalam Folder Komponen. Jadi file Layanan saya menjadi semacam Manajer Acara atau Antarmuka Acara, jadi saya dapat mengetahui secara sekilas peristiwa mana yang dapat saya ikuti pada komponen saat ini.

Saya tahu .. Mungkin saya sedikit pengembang kuno. Tetapi ini bukan bagian dari pola pengembangan Event Driven, ini adalah bagian dari keputusan arsitektur perangkat lunak proyek khusus Anda.

Beberapa orang lain mungkin berpikir bahwa menggunakan Observables secara langsung itu keren. Dalam hal ini langsung saja dengan Observables. Anda bukan pembunuh berantai yang melakukan ini. Kecuali jika Anda seorang pengembang psikopat, Sejauh ini Program bekerja, lakukanlah.

Claudio Ferraro
sumber