Angular2 зачем использовать @Output вместо @Input для обратных вызовов

#angular #typescript

#angular #typescript

Вопрос:

Я изучаю Angular2, проработав с Angular1 пару лет. Я создаю компонент формы кредитной карты, основная цель которого — изучить пару ключевых понятий в Angular2. Компонент должен обрабатывать все форматирование и возвращать токен Stripe через обратный вызов. Я понял, что могу обрабатывать обратные вызовы двумя способами.

Использование параметра @Output

В моем компоненте я определяю выходную переменную и использую ее, как в этом примере:

 export class CreditCardForm{
    ....
    @Output () callback = new EventEmitter();
    ....

    doCallback(){
        this.callback.emit({data: 123});
    }
}

// Parent view
<credit-card-form (callback)="creditCardCallback($event)"></credit-card-form>
 

Использование переменной @Input

Однако я мог бы просто передать метод обратного вызова ( creditCardCallback , используемый в родительском шаблоне) во входную переменную, например:

 export class CreditCardForm{
    ....
    @Input () callback;
    ....

    doCallback(){
        this.callback({data: 123});
    }
}

// Parent view
<credit-card-form [callback]="creditCardCallback"></credit-card-form>
 

Вопрос

Зачем мне использовать @Output over @Input ? Чего я добиваюсь, используя @Output переменные вместо этого? Насколько я вижу, это просто добавляет накладные расходы из-за необходимости использовать EventEmitter класс.

Ответ №1:

Всегда есть более одного способа скинуть кошку. Однако, на мой взгляд, использование @Output имеет следующие преимущества:

  • Удобочитаемость кода: при использовании рекомендуемого стиля легче узнать поток данных.
  • Разъединение: например, для обычного события в вашем случае вы можете иметь большую гибкость при обработке отправленного события @Output ParentComponent :
  • И последнее, но не менее важное — он включает синтаксис банана в поле: скажем, у ChildComponent вас есть:

@Input() creditCardValue: string;
@Output() creditCardValueChange: EventEmitter<string>;

Тогда у вас может быть двусторонняя привязка в вашем ParentComponent легко:

 <credit-card-form [(creditCardValue)]="creditCardVal"></credit-card-form>
 

Комментарии:

1. Большое вам спасибо за отличный ответ! Это убеждает меня использовать @Output для обратных вызовов. Ваш ответ также научил меня, что есть такая фраза, как «синтаксис банана в коробке», что приводит к некоторым забавным картинкам при поиске в Google 🙂

2. Я также предполагаю, что, поскольку with @Output вы используете соединение сообщений в отличие от внешнего соединения with @Input . Итак, если в каком-то случае @Input параметр не определен в дочернем элементе (не имеет родительского элемента?), Тогда вам не нужно беспокоиться ни о каких this.callback amp;amp; this.callback.call(...) noOp методах или. Но я могу видеть использование только @Output для выбросов событий — но я думаю, что его плохой дизайн для определения ваших типов событий в масштабе компонентов, а не в масштабе приложения; это создаст энтропию для вашего приложения и его инженеров .

3. Спасибо, Гарри! Просто поражен, потому что я искал именно это. Моя маленькая проблема: как перейти отсюда на ваш более приятный стиль? <item (data)=»handleUpdated($event)» [data]=»name» ></item>

4. У меня есть это! Теперь я использую банановый стиль 😉 @Input() данные: строка; @Output(this.data) Изменение данных = новый EventEmitter();

5. @gtamborero Всегда приятно, когда ты можешь решить свою собственную проблему, верно? 😉

Ответ №2:

Имхо, @Output это ОГРОМНЫЙ недостаток дизайна, так как вы не можете реагировать на результат или обрабатывать его. Примером этого недостатка номер один является нажатие кнопки. При нажатии кнопка должна быть отключена в 99% случаев, когда происходит действие. Как только действие будет выполнено, кнопка должна быть снова включена. Это то, что вы хотите обработать в самом элементе, а не в родительском. С @Output , ты не можешь этого сделать. Используя функцию действия as @Input , вы можете сделать это! И если ваша функция действия возвращает наблюдаемое или обещание, вы можете легко его дождаться. Создать пользовательскую директиву, которая обрабатывает это отключение, несложно, и, таким образом, вы можете использовать [click] везде, и она будет вести себя именно так.

РЕДАКТИРОВАТЬ: я не говорю @Output , что он не используется, но не для действий, которых вам нужно ждать и т.д…. Присвоение имени вашему @Input s good также проясняет поток, например onDelete , etc…

Комментарии:

1. Я не поклонник семантики и лично предпочитаю обратные вызовы в стиле react, но чтобы конкретно ответить на ваши проблемы, нет причин, по которым ваше исходное событие должно напрямую ссылаться на отправителя. Ознакомьтесь с примером документов здесь: angular.io/guide /. … Дочерний компонент привязывает событие щелчка к локальной для дочернего компонента функции-обработчика. Дочерний элемент, в свою очередь, вызывает emit эмиттер. Это, безусловно, было бы хорошим местом для добавления любого типа проверки, который вы можете себе представить, для короткого замыкания распространения события.

2. Да, верно, но вы не можете контролировать результат функции. Я всегда вводлю действия, которые являются функциями, в компонент, поэтому компонент может их выполнять, но не должен знать, что именно будет сделано. Такие действия возвращают наблюдаемое, потому что может выполняться асинхронное действие. Итак, нам нужен способ отключить кнопку и т. Д. …. в зависимости от состояния действия, и вы не можете сделать это с помощью Output. С помощью Output вам всегда нужно сохранять переменные в вашем компоненте, чтобы сделать это, с помощью Input и [click] вы можете указать это в директиве, чтобы обработать это для вас.