Как правильно использовать EventEmitter?


225

Я читал такие вопросы, как Access EventEmitter Service внутри CustomHttp, где пользователь использует EventEmitter в своем сервисе, но ему было предложено в этом комментарии не использовать его и использовать вместо него Observables непосредственно в своих сервисах.

Я также прочитал этот вопрос, где решение предлагает передать EventEmitter ребенку и подписаться на него.

Мой вопрос: я должен или не должен подписываться вручную на EventEmitter? Как я должен использовать это?



2
Хороший ответ от Марка, как обычно, но на самом деле он не объясняет, почему я объяснил. Я не против его закрытия, но сначала я хочу узнать его мнение. @MarkRajcok мысли?
Эрик Мартинес

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

@MarkRajcok Мне нравится этот заголовок, но он не будет соответствовать текущему ответу, поэтому я обязательно обновлю его позже, добавлю примеры того, как его использовать, а как нет, чтобы он имел больше смысла. Спасибо за ваш отзыв :)
Эрик Мартинес

@MarkRajcok отредактировано в соответствии с предложением (y), (скопируйте и вставьте предложенное название, все кредиты вам).
Эрик Мартинес

Ответы:


343

TL; DR :

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

Ответ:

Нет, вы не должны подписываться на него вручную.

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

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

Это действительно ясно указано в документации к EventEmitter.

Используйте директивы и компоненты для создания пользовательских событий.

Что плохого в его использовании?

Angular2 никогда не гарантирует нам, что EventEmitter останется наблюдаемым. Так что это означает рефакторинг нашего кода, если он меняется. Единственный API, к которому мы должны получить доступ - это его emit()метод. Мы никогда не должны подписываться вручную на EventEmitter.

Все вышеизложенное более четко видно в комментарии этого Уорд Белла (рекомендуется прочитать статью и ответ на этот комментарий). Цитирование для справки

НЕ рассчитывайте на то, что EventEmitter останется наблюдаемым!

НЕ рассчитывайте на тех операторов Observable, которые будут там в будущем!

Они скоро будут устаревшими и, вероятно, будут удалены перед выпуском.

Используйте 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.
themathmagician

1
@Eric: как не использовать его в вашем примере, очевидно, зачем нам нужен декоратор @Output в сервисе?
trungk18

1
@themathmagician После небольшого исследования, я нашел здесь , что directivesключевое слово , так как устарел. Используйте declarationsключевое слово в @NgModuleсоответствии с указаниями здесь или здесь
cjsimon

5
Любой комментарий к более свежему ответу Тоби? Я предполагаю, что его ответ должен быть принят в наши дни.
Арджан

7
@Eric Когда вы написали этот ответ, вы написали: «Они скоро устареют и, вероятно, будут удалены перед выпуском», цитирует Уорд Белл. Но это было заявлено 2 года назад, и теперь у нас есть angular6. Это утверждение применяется до сих пор? Я продолжаю видеть в официальном документе, что у EventEmitter все еще есть метод подписки (), поэтому я думаю, что если бы Google хотел прекратить основывать EE на предметах Rxjs, они бы уже сделали это. Так вы думаете, что ваш первоначальный ответ все еще хорошо вписывается в текущее состояние Angular?
Nad G

101

Да, идти вперед и использовать его.

EventEmitterявляется открытым, документированным типом в окончательном Angular Core API. Основано ли это на 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 в этом примере?
Botis

6
Сейчас мы работаем над Angular v6, и EventEmmiter не устарел и не был удален, поэтому я бы сказал, что он безопасен в использовании. Тем не менее, я вижу преимущества в изучении того, как использовать Observables из RxJS.
Дэвид Меза

Я вижу это как «если вы используете EventEmitter за пределами @Output, не нужно спешить менять его на что-то другое, поскольку API является стабильным банкоматом»; если у вас есть время или перерывы в API, вам придется его изменить (но имейте в виду, что для угловых изменений публичный стабильный API (emit and subscribe) не распространен). Также придерживайтесь общедоступных API, не
обращайтесь

1
Предположение, что что-то безопасно использовать из-за того, что «не было удалено из Angular» или «хорошо задокументировано», неверно, так же как и политика nono, предложенная выше. Вы создаете проект не по причине будущих версий angular. Снаружи существует множество необслуживаемых платформ, все еще работающих в Интернете. Версия фреймворка не делает разработчиков, которые работали на этих платформах, менее разработчиками или разработчиками категории B.
Клаудио Ферраро

4

Если вы хотите взаимодействовать между компонентами, вам нужно знать, что такое @Input, @Output, EventEmitter и Subjects.

Если отношения между компонентами являются родительскими и дочерними, или наоборот, мы используем @input & @output с генератором событий.

@output испускает событие, и вам нужно отправить его с помощью генератора событий.

Если это не отношения между родителями и детьми ... тогда вы должны использовать предметы или через общий сервис.


0

Нет: nono и нет: yesyes. Истина в середине И нет причин бояться из-за следующей версии Angular.

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

Я знаю .. Может быть, я немного старомодный разработчик. Но это не часть модели разработки, управляемой событиями, это часть решений по архитектуре программного обеспечения вашего конкретного проекта.

Некоторые другие ребята могут подумать, что использовать Observables напрямую - это круто. В этом случае перейдите непосредственно к Observables. Вы не серийный убийца, делающий это. Если вы не разработчик психопатов, пока программа работает, делайте это.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.