Яке правильне використання EventEmitter?


225

Я читав такі питання, як Access EventEmitter Service всередині CustomHttp, де користувач використовує EventEmitter у своїй службі, але він запропонований у цьому коментарі не використовувати його, а використовувати замість Observables безпосередньо у своїх послугах.

Я також прочитав це питання, де рішення пропонує передати EventEmitter дитині та підписатися на нього.

Моє питання тоді: чи повинен я чи не повинен підписуватись вручну на EventEmitter? Як я повинен його використовувати?



2
Гарна відповідь Марка, як завжди, але насправді він не пояснює, чому я пояснив. Я не проти його закриття, але спочатку хочу його думку. @MarkRajcok думки?
Ерік Мартінес

Я хотів би, щоб це було відкритим (і я впевнений, що я вкажу тут людей - я просто відредагував свою іншу відповідь, щоб вказати тут!). У вашій відповіді є додаткова інформація. Хоча я хотів би два заголовки питань ... інше - "Яке правильне використання EventEmitter?"
Марк Райкок

@MarkRajcok мені подобається цей заголовок, але він би не відповідав поточній відповіді, тому я обов’язково оновлю його пізніше, додаю приклади, як ним користуватися, а як ні, щоб це мало більше сенсу. Дякуємо за ваш відгук :)
Ерік Мартінес

@MarkRajcok відредаговано так, як було запропоновано (y), (скопіюйте та вставте запропонований заголовок, усі кредити вам).
Ерік Мартінес

Відповіді:


342

TL; DR :

Ні, не підписуйтесь на них вручну, не використовуйте їх у сервісах. Використовуйте їх, як показано в документації, лише для передачі подій в компонентах. Не перемагайте абстракцію кута.

Відповідь:

Ні, ви не повинні підписатися на нього вручну.

EventEmitter - це кутова абстракція2, і єдина його мета - випромінювати події в компонентах. Цитуючи коментар Роб Вормальд

[...] EventEmitter - це дійсно кутова абстракція, і його слід використовувати в значній мірі лише для передачі користувацьких подій у компонентах. В іншому випадку просто використовуйте Rx так, ніби це була будь-яка інша бібліотека.

Це сказано дійсно ясно в документації EventEmitter.

Використовуйте директивами та компонентами для передачі користувацьких подій.

Що не так у використанні?

Angular2 ніколи не гарантує нам, що EventEmitter продовжить бути спостережуваним. Отже, це означає рефакторинг нашого коду, якщо він зміниться. Єдиний API, до якого ми маємо отримати доступ, це йогоemit() метод. Ми ніколи не повинні підписуватись на EventEmitter вручну.

Все сказане вище зрозуміло в коментарі Уорда Белла (рекомендується прочитати статтю та відповідь на цей коментар). Цитуючи довідку

НЕ розраховуйте на те, що EventEmitter продовжує бути спостерігачем!

НЕ розраховуйте на те, що ті оператори, які спостерігаються, будуть там у майбутньому!

Вони будуть застарілі найближчим часом і, ймовірно, будуть видалені перед випуском.

Використовуйте EventEmitter лише для прив'язки подій між дочірнім та батьківським компонентом. Не підписуйтесь на це. Не вимагайте жодного з цих методів. Тільки дзвонітьeve.emit()

Його коментар узгоджується з коментарем Роба давно.

Отже, як правильно ним користуватися?

Просто використовуйте його для передачі подій зі свого компонента. Погляньте на наступний приклад.

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

Як не користуватися ним?

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

Зупиніться прямо тут ... ви вже помиляєтесь ...

Сподіваємось, що ці два простих приклади пояснять правильне використання EventEmitter.


1
Що ви маєте на увазі під directives : [Child]визначенням компонента? Здається, це не компілюється, і я не можу знайти це описано в документації Angular2.
тематичний лікар

1
@Eric: Як не використовувати його у вашому прикладі, очевидно, чому нам потрібен декоратор "@Output" в сервісі?
trungk18

1
@themathmagician Після невеликого дослідження, я знайшов тут , що directivesключове слово , так як застарів. Використовуйте declarationsключове слово, @NgModuleяк вказано тут чи тут
cjsimon

5
Будь-який коментар до останньої відповіді Тобі? Я здогадуюсь, його відповідь сьогодні має бути прийнятою.
Ар'ян

7
@Eric Коли ви писали цю відповідь, ви писали: "Вони будуть застаріли найближчим часом і, ймовірно, будуть видалені перед випуском", цитуючи Уорда Белла. Але це було сказано 2 роки тому, і зараз у нас є кутовий6. Чи діє це твердження і зараз? Я продовжую бачити в офіційному документі, що у EventEmitter все ще є метод Subscri (), тому я думаю, що якби Google захотів перестати базувати EE на темах Rxjs, вони це вже зробили. Отже, ви вважаєте, що ваша оригінальна відповідь все ще добре відповідає поточному стану Angular?
Nad G

101

Так, ідіть і використовуйте його.

EventEmitterє загальнодоступним, задокументованим типом у заключному API Angular Core. Незалежно від того, ґрунтується чи ні, не Observableмає значення; якщо це задокументовано emitіsubscribe методи відповідають тому, що вам потрібно, тоді вперед і користуйтеся цим.

Як також зазначено в документах:

Використовує Rx.Observable, але забезпечує адаптер для роботи, як зазначено тут: https://github.com/jhusain/observable-spec

Як тільки довідкова реалізація специфікації буде доступна, переключіться на неї.

Тому вони хотіли Observable подібного об’єкта, який поводився певним чином, реалізували його та оприлюднили. Якби це була лише внутрішня кутова абстракція, яку не слід використовувати, вони б не оприлюднили її.

Існує багато випадків, коли корисно мати випромінювач, який надсилає події певного типу. Якщо це ваш випадок використання, перейдіть до цього. Якщо / коли доступна довідкова реалізація специфікацій, на які вони посилаються, це має бути заміною, що випадає, як і будь-який інший поліфайл.

Просто переконайтеся, що генератор, який ви передаєте subscribe()функції, слідує за пов'язаними характеристиками. Повертається об'єкт гарантовано має unsubscribeметод, який слід викликати, щоб звільнити будь-які посилання на генератор (це в даний час об'єкт RxJs,Subscription але це дійсно деталі реалізації, від яких не слід залежати).

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

Усі чітко виражені прогнози приреченості та похмурості, схоже, випливають із одного коментаря щодо переповнення стека від одного розробника щодо попередньо випущеної версії Angular 2.


2
Це звучить розумно - хто ще хоче зважитися на цьому? підписатися - це загальнодоступний метод емітеру подій?
Шосон

Гаразд, це публічно, тому ми можемо ним користуватися. Але чи є якісь практичні причини використовувати EventEmitter над Observable у цьому прикладі?
Ботіс

6
Зараз ми перебуваємо на Angular v6, і EventEmmiter не було застаріле або видалено, тому я б сказав, що це безпечно у використанні. Однак я бачу переваги в тому, як навчитися використовувати Спостереження з RxJS.
Девід Меза

Я вважаю це "якщо ви використовуєте EventEmitter за межами @Output, не потрібно поспішати змінювати його на щось інше, оскільки api стабільний банкомат"; якщо у вас є час або розрив api, вам доведеться його змінити (але майте на увазі, що для кутових змін публічний стабільний api (емітувати та підписатися) не є звичайним). Також дотримуйтесь загальнодоступних api, не отримуйте доступу до методів Subject або Observable, які не визначені в EventEmitter, щоб залишатися на безпечнішій стороні
acidghost

1
Припущення про те, що щось безпечно використовувати через те, що "не було видалено з кутового" або "добре задокументоване", є помилковим, а також запропонованою вище політикою nono. Ви створюєте проект не з причини майбутніх версій кутових. На вулиці є ще багато необроблених платформ, які все ще працюють в Інтернеті. Версія фреймворку не робить розробників, які працювали на цих платформах, менш розробниками або розробниками категорії B.
Клаудіо Ферраро

4

Коли ви хочете мати взаємодію між компонентами, вам потрібно знати, що таке @ вхід, @ вихід, EventEmitter та суб'єкти.

Якщо співвідношення між компонентами є батьківським дочірнім або навпаки, ми використовуємо @input & @output з емітером подій.

@output посилає подію, і її потрібно випромінювати, використовуючи емітер події.

Якщо це не стосунки з батьками-дітьми .. тоді вам доведеться користуватися предметами або через загальну службу.


0

Немає: nono і no: yesyes. Правда в середині І немає причин лякатися через чергову версію Angular.

З логічної точки зору, якщо у вас є компонент і ви хочете повідомити інші компоненти про те, що щось відбувається, подія повинна бути знята, і це можна зробити будь-яким способом, який ви (розробник) вважаєте, що це слід зробити. Я не бачу причини, щоб не використовувати його, і я не бачу причини, щоб використовувати його за будь-яку ціну. Також ім'я EventEmitter пропонує мені подію, яка відбувається. Зазвичай я використовую його для важливих подій, що відбуваються в Компоненті. Я створюю Службу, але створюю файл служби всередині папки компонентів. Таким чином мій сервісний файл стає свого роду менеджером подій або інтерфейсом подій, тож я можу зрозуміти, на яку подію я можу підписатись на поточний компонент.

Я знаю .. Можливо, я трохи старомодний розробник. Але це не є частиною моделі розвитку, керованої подіями, це частина рішення архітектури програмного забезпечення вашого конкретного проекту.

Деякі інші хлопці можуть подумати, що використовувати Observables безпосередньо - це класно. У такому випадку продовжуйте роботу безпосередньо з спостерігачами. Ви не серійний вбивця, який робить це. Якщо ви не розробник психопатів, поки програма працює, робіть це.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.