En En

Жизненный цикл компонента


Польза компонентов заключается в том, что они позволяют полностью контролировать какую-либо часть DOM. Это дает возможность напрямую манипулировать DOM, перехватывать события браузера и реагировать на них, а также использовать в приложении Ember сторонние библиотеки JavaScript.

Так как компоненты отображаются, затем отображаются повторно и, наконец, удаляются, в Ember есть hooks жизненного цикла, которые позволяют запускать код в определенное время существования компонента.

Чтобы извлечь максимальную пользу из компонента, важно знать эти методы жизненного цикла.

Порядок вызова hook'ов жизненного цикла

Ниже перечислены hook'и жизненного цикла компонента в порядке их исполнения согласно сценарию отображения.

Начальное отображение

  1. init
  2. didReceiveAttrs
  3. willRender
  4. didInsertElement
  5. didRender

Повторное отображение

  1. didUpdateAttrs
  2. didReceiveAttrs
  3. willUpdate
  4. willRender
  5. didUpdate
  6. didRender

Удаление компонента

  1. willDestroyElement
  2. willClearRender
  3. didDestroyElement

Примеры hook'ов жизненного цикла

Ниже мы привели несколько примеров того, как можно использовать hook'и жизненного цикла компонентов.

Сброс состояния представления при изменении атрибута с помощью didUpdateAttrs

didUpdateAttrs запускается при изменении атрибутов компонента, а не в тот момент, когда компонент отображается повторно, через component.rerender, component.set или изменения в моделях или службах, которые использует шаблон.

didUpdateAttrs вызывается до повторного отображения. Этот hook можно использовать, чтобы выполнять код при изменении определенных атрибутов. Этот hook может быть эффективной альтернативой observer (наблюдателю), так как он запускается до повторного отображения, но после изменения атрибута.

Примером этого сценария в действии служит компонент редактора профилей. Когда вы редактируете одного пользователя и его атрибут меняется, можно применить didUpdateAttrs, чтобы сбросить любое состояние ошибки, которое возникло от редактирования предыдущего пользователя.

/app/templates/components/profile-editor.hbs

<ul class="errors">
  {{#each errors as |error|}}
    <li>{{error.message}}</li>
  {{/each}}
</ul>
<fieldset>
  {{input name="user.name" value=name change=(action "required")}}
  {{input name="user.department" value=department change=(action "required")}}
  {{input name="user.email" value=email change=(action "required")}}
</fieldset>

/app/components/profile-editor.js

import Ember from 'ember';

export default Ember.Component.extend({
  init() {
    this._super(...arguments);
    this.errors = [];
  },

  didUpdateAttrs() {
    this._super(...arguments);
    this.set('errors', []);
  },

  actions: {
    required(event) {
      if (!event.target.value) {
        this.get('errors').pushObject({ message: `${event.target.name} is required`});
      }
    }
  }
});

Форматирование атрибутов компонента с помощью didReceiveAttrs

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

Так как hook didReceiveAttrs вызывается при обновлении атрибутов компонента, будь то этап отображения или повторного отображения, вы можете использовать hook в качестве эффективной альтернативы наблюдателю. Он гарантирует, что код будет выполнен при изменении атрибутов.

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

import Ember from 'ember';

export default Ember.Component.extend({
  didReceiveAttrs() {
    this._super(...arguments);
    const profile = this.get('data');
    if (typeof profile === 'string') {
      this.set('profile', JSON.parse(profile));
    } else {
      this.set('profile', profile);
    }
  }
});

Интеграция сторонних библиотек с помощью didInsertElement

Предположим, что вы хотите интегрировать любимую библиотеку с элементами выбора даты в проект Ember. Обычно сторонние библиотеки JS/jQuery требуют привязки к элементу DOM. Где же находится наилучшее место для инициализации и подключения библиотеки?

После того как компонент успешно представляет вспомогательный элемент HTML в DOM, он запускает hook didInsertElement().

Ember гарантирует, что к моменту вызова didInsertElement():

  1. Элемент компонента будет создан и включен в модель DOM.
  2. Элемент компонента будет доступен через метод $() компонента.

Метод $() компонента позволяет вам получить доступ к элементу DOM компонента путем возвращения элемента JQuery. Например, вы можете установить атрибут с помощью метода jQuery attr():

didInsertElement() {
  this._super(...arguments);
  this.$().attr('contenteditable', true);
}

По умолчанию $() вернет объект jQuery для корневого элемента компонента, но вы можете также указать дочерние элементы в пределах шаблона компонента с помощью передачи селектора:

didInsertElement() {
  this._super(...arguments);
  this.$('div p button').addClass('enabled');
}

Инициализируем элемент выбора даты с помощью переопределения метода didInsertElement().

Библиотеки элементов выбора даты подключаются к элементу <input>. Поэтому мы будем использовать jQuery, чтобы найти подходящие входные данные в пределах нашего шаблона компонента.

didInsertElement() {
  this._super(...arguments);
  this.$('input.date').myDatePickerLib();
}

didInsertElement() — хорошее место для подключения приемников событий. Это особенно полезно для индивидуально настроенных событий или других событий браузера, у которых нет встроенного обработчика событий.

Например, у вас при отображении компонента запускаются какие-либо индивидуально настроенные CSS-анимации, и вы хотите обработать сброс после их отображения:

didInsertElement() {
  this._super(...arguments);
  this.$().on('animationend', () => {
    $(this).removeClass('.sliding-anim');
  });
}

Стоит отметить несколько вещей касательно hook'а didInsertElement():

  • Он запускается только один раз, кода элемент компонента отображается впервые.
  • Если ваши компоненты вложены в другие компоненты, hook didInsertElement() всегда будет вызываться сначала в дочерних компонентах, а затем в родительских.
  • Назначение свойств компоненту в didInsertElement() запускает повторное отображение, и ради производительности этого делать не следует.
  • Технически, didInsertElement() — событие, которое можно перехватить с помощью on(). Но рекомендуется переопределять сам исходный метод, в особенности когда важен порядок выполнения.

Обновление отображенной DOM с помощью didRender

Hook didRender вызывается во время отображения и повторного отображения, когда шаблон отображен и DOM обновлена. Вы можете применить этот hook, чтобы выполнить последующую обработку компонента в DOM после его обновления.

В этом примере показан компонент списка, который нужно прокрутить на выбранный элемент после отображения. Так как прокручивание до определенного места основано на позициях в DOM, нам нужно убедиться, что список отображается до прокручивания. Мы можем сначала отобразить этот список, а затем настроить прокрутку.

Компонент ниже принимает список элементов и отображает их на экране. Кроме того, он принимает объект, который указывает, какой элемент выбран, а затем устанавливает прокрутку к этому элементу.

{{selected-item-list items=items selectedItem=selection}}

При отображении компонент будет проходить в цикле данный список и применять класс к выбранному элементу.

/app/templates/components/selected-item-list.hbs

{{#each items as |item|}}
  <div class="list-item {{if item.isSelected 'selected-item'}}">{{item.label}}</div>
{{/each}}

Прокрутка происходит в didRender, где он будет прокручивать контейнер компонента на элемент с выбранным именем класса.

/app/components/selected-item-list.js

import Ember from 'ember';

export default Ember.Component.extend({
  className: 'item-list',

  didReceiveAttrs() {
    this._super(...arguments);
    this.set('items', this.get('items').map((item) => {
      if (item.id === this.get('selectedItem.id')) {
        item.isSelected = true;
      }
      return item;
    }));
  },

  didRender() {
    this._super(...arguments);
    this.$('.item-list').scrollTop(this.$('.selected-item').position.top);
  }
});

Отключение и удаление элементов компонента с помощью willDestroyElement

Когда компонент обнаруживает, что пришло время удалиться из DOM, Ember запускает метод willDestroyElement(), который позволяет реализовать любую логику удаления.

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

{{#if falseBool}}
  {{my-component}}
{{/if}}

Используем этот hook, чтобы убрать элемент выбора даты и приемник событий выше:

willDestroyElement() {
  this._super(...arguments);
  this.$().off('animationend');
  this.$('input.date').myDatepickerLib().destroy();
}

Комментарии (0)

    Выделите опечатку и нажмите Ctrl + Enter, чтобы отправить сообщение об ошибке.