Новая модель компонентов

В Ember.js компоненты — это строительные блоки интерфейсов. Они представляют собой независимые элементы, инкапсулирующие логику и представление, что позволяет организовать код в чистую и повторно используемую структуру. В Ember 3.15 была введена новая модель компонентов, основанная на ES-классах, что значительно упростило создание и использование компонентов в приложении.

Основные изменения

До появления новой модели компоненты в Ember.js создавались с использованием объектов и синтаксиса Ember.Component. С выходом новой модели были введены классы ES6, что стало стандартом для определения компонентов. Новая модель упрощает работу с компонентами, делает их более гибкими и понятными для разработчиков, знакомых с современным JavaScript.

Сейчас компоненты создаются как обычные классы JavaScript с помощью синтаксиса классов ES6:

import Component from '@glimmer/component';

export default class MyComponent extends Component {
  // Логика компонента
}

Здесь @glimmer/component — это базовый класс, от которого наследуются компоненты, использующие новую модель. Это облегчает работу с состоянием компонента и его взаимодействием с шаблонами.

Структура компонента

Компонент состоит из двух основных частей: класса и шаблона. Класс компонента управляет его состоянием и логикой, в то время как шаблон (обычно с расширением .hbs) отвечает за отображение данных.

Класс компонента

Класс компонента может содержать методы для работы с состоянием, а также обработчики событий. Пример класса компонента, который управляет состоянием:

import Component from '@glimmer/component';

export default class CounterComponent extends Component {
  count = 0;

  increment() {
    this.count++;
  }

  decrement() {
    this.count--;
  }
}

Этот класс управляет состоянием счетчика с переменной count и методами для увеличения и уменьшения значения.

Шаблон компонента

Шаблон компонента написан на языке Handlebars и привязывает данные из класса компонента к DOM. В примере ниже отображаются кнопки для увеличения и уменьшения значения счетчика:

<button {{on "click" this.increment}}>+</button>
<button {{on "click" this.decrement}}>-</button>
<p>Счётчик: {{this.count}}</p>

Здесь используется директива {{on}} для привязки обработчиков событий к элементам DOM.

Характеристики новой модели

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

  2. Гибкость шаблонов. Использование шаблонов Handlebars позволяет легко связывать данные и методы компонента с HTML-разметкой. Такой подход минимизирует вероятность ошибок и повышает удобство в работе с шаблонами.

  3. Поддержка событий. Новый синтаксис для обработки событий, например, через директиву {{on}}, позволяет добавлять обработчики событий прямо в шаблоне, улучшая читаемость кода и облегчая поддержку.

  4. Поддержка вычисляемых свойств. В новой модели компоненты могут использовать геттеры и сеттеры для создания вычисляемых свойств. Это удобно для вычисления значений на основе состояния компонента.

Взаимодействие с родительскими компонентами

Компоненты могут передавать данные родительским компонентам с помощью аргументов. Эти аргументы передаются при создании компонента:

<Counter @startValue={{this.startValue}} />

В этом примере компонент Counter получает аргумент startValue, который передается родительским компонентом. В классе компонента можно использовать его как обычное свойство:

import Component from '@glimmer/component';

export default class CounterComponent extends Component {
  get count() {
    return this.args.startValue;
  }
}

Управление состоянием

Состояние компонента в новой модели управляется напрямую через свойства класса. Однако для сложных взаимодействий и асинхронных операций рекомендуется использовать сервисы или стор для управления состоянием на более высоком уровне. Ember предоставляет инструменты, такие как Ember Data и tracked properties, для более сложных случаев работы с состоянием.

В случае использования tracked properties, можно отслеживать изменения данных в компонентах. Для этого в классе компонента используется декоратор @tracked:

import { tracked } from '@glimmer/tracking';

export default class CounterComponent extends Component {
  @tracked count = 0;
}

Когда значение count изменяется, Ember автоматически перерисует компоненты, использующие это значение.

Внедрение сервисов

Компоненты могут использовать сервисы для получения данных или управления состоянием на уровне всего приложения. Сервисы внедряются в компоненты с помощью декоратора @service. Это позволяет компонентам обращаться к внешним данным или функциям, не заботясь о деталях их реализации:

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';

export default class MyComponent extends Component {
  @service store;

  get allRecords() {
    return this.store.findAll('model');
  }
}

В этом примере компонент использует сервис store, чтобы получить все записи модели. Это позволяет абстрагировать доступ к данным и сделать компонент более гибким и независимым.

Шаблоны компонентов

В шаблоне компонента доступна привязка к свойствам и методам класса компонента. Ember.js также предоставляет функциональность для условных выражений и циклов, позволяя легко работать с динамическим содержимым.

Пример использования условных выражений:

{{#if this.isVisible}}
  <p>Элемент видим</p>
{{else}}
  <p>Элемент скрыт</p>
{{/if}}

Кроме того, можно использовать циклы для работы с массивами данных:

<ul>
  {{#each this.items as |item|}}
    <li>{{item.name}}</li>
  {{/each}}
</ul>

Совместимость с предыдущими версиями

Новая модель компонентов сохраняет совместимость с предыдущими версиями Ember.js, однако рекомендуется использовать новые возможности фреймворка для более чистого и современного кода. Старая модель компонентов все еще поддерживается, но новая модель значительно улучшает производительность и читаемость кода, что особенно важно в крупных приложениях.

Преимущества новой модели

  1. Чистота и читаемость кода. Использование классов и ES6 синтаксиса делает код компонентов легче для понимания и поддержки.
  2. Оптимизация производительности. Новый подход к отслеживанию состояния и обновлению DOM позволяет улучшить производительность приложения, особенно в сложных интерфейсах.
  3. Универсальность и гибкость. Простой доступ к аргументам и сервисам, а также поддержка вычисляемых свойств делают компонент более гибким и мощным инструментом для построения интерфейсов.

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