Передача данных между компонентами

FAST Element — современная библиотека для создания веб-компонентов на базе стандартов Web Components. Одной из ключевых задач при разработке интерфейсов является обеспечение эффективной передачи данных между компонентами, как между родительскими и дочерними, так и между «равноправными» компонентами.


Свойства (Properties) и атрибуты (Attributes)

В FAST Element данные чаще всего передаются через свойства компонента. Свойства объявляются с помощью декоратора @attr или через объект observedAttributes.

import { FASTElement, html, css, attr } from "@microsoft/fast-element";

class UserCard extends FASTElement {
  @attr name;
  @attr age;
}

UserCard.define({
  name: "user-card",
  template: html<UserCard>`<div>${x => x.name} (${x => x.age})</div>`,
});

Особенности передачи через свойства:

  • Прямое связывание данных: родитель может напрямую установить значение свойства дочернего компонента через DOM.
  • Автоматическая реактивность: изменения значения свойства вызывают обновление шаблона компонента.
  • Синхронизация с атрибутами: при использовании @attr значение свойства автоматически синхронизируется с HTML-атрибутом, что упрощает декларативное использование компонента.
<user-card name="Иван" age="30"></user-card>

Здесь значения атрибутов name и age автоматически станут значениями свойств компонента.


События для обратной связи

Для передачи данных от дочернего компонента к родительскому в FAST Element используется механизм событий. Обычно создаются кастомные события (CustomEvent).

import { FASTElement, html, attr } from "@microsoft/fast-element";

class CounterButton extends FASTElement {
  count = 0;

  increment() {
    this.count++;
    this.$emit("count-changed", { detail: this.count });
  }
}

CounterButton.define({
  name: "counter-button",
  template: html<CounterButton>`
    <button @click="${x => x.increment()}">Нажато: ${x => x.count}</button>
  `,
});

Особенности:

  • this.$emit(eventName, options) — удобный метод FAST Element для генерации кастомного события.
  • Событие может быть направлено вверх по DOM и прослушано родительским компонентом.
  • detail содержит передаваемые данные.
<counter-button @count-changed="${e => console.log(e.detail)}"></counter-button>

Шаблонное связывание (Template Binding)

FAST Element использует объявленные свойства для реактивного связывания данных в шаблоне. Это позволяет автоматически обновлять интерфейс при изменении данных.

class TodoItem extends FASTElement {
  @attr title;
  @attr done = false;

  toggle() {
    this.done = !this.done;
  }
}

TodoItem.define({
  name: "todo-item",
  template: html<TodoItem>`
    <div>
      <input type="checkbox" ?checked="${x => x.done}" @change="${x => x.toggle()}">
      <span>${x => x.title}</span>
    </div>
  `,
});

Ключевые моменты:

  • ?checked связывает булевое свойство с атрибутом HTML.
  • Любое изменение свойства автоматически пересчитывает шаблон.
  • Такой подход позволяет передавать данные между компонентами через свойства и события без дополнительных библиотек.

Слоты (Slots) и композиция

Для сложной передачи контента можно использовать слоты, которые позволяют компоненту принимать вложенный DOM от родителя.

const template = html`
  <div class="card">
    <slot name="header"></slot>
    <slot></slot>
    <slot name="footer"></slot>
  </div>
`;

class Card extends FASTElement {}
Card.define({ name: "app-card", template });

Пример использования:

<app-card>
  <h2 slot="header">Заголовок</h2>
  <p>Основной текст</p>
  <div slot="footer">Подвал</div>
</app-card>

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


Контекст и сервисы

Для передачи данных между несвязанными компонентами можно использовать контекст (Context API), встроенный в FAST Element. Контексты позволяют создавать сервисы, доступные нескольким компонентам без прямого родительского связывания.

import { provide, consume } from "@microsoft/fast-element";

class ThemeProvider extends FASTElement {
  theme = "dark";

  connectedCallback() {
    super.connectedCallback();
    provide(this, "theme", this.theme);
  }
}

class ThemedButton extends FASTElement {
  @consume theme;

  render() {
    return html`<button class="${x => x.theme}">Кнопка</button>`;
  }
}

Преимущества:

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

Реактивность и наблюдение

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

class Profile extends FASTElement {
  @attr username;

  usernameChanged(oldValue, newValue) {
    console.log(`Username изменен с ${oldValue} на ${newValue}`);
  }
}
  • Метод с суффиксом Changed автоматически вызывается при изменении соответствующего свойства.
  • Позволяет реагировать на изменения данных без внешних слушателей событий.

Сравнение подходов

Подход Направление передачи Особенности
Свойства / атрибуты Родитель → Дочерний Прямая реактивная связь, синхронизация с DOM
События Дочерний → Родитель Кастомные события, легко подписываться на изменения
Слоты Родитель → Дочерний (DOM) Позволяет передавать сложные структуры
Контекст Несвязанные компоненты Глобальная подписка на данные, централизованное управление

Использование этих механизмов в сочетании позволяет создавать гибкие, реактивные и масштабируемые интерфейсы на FAST Element, минимизируя количество ручного связывания и дублирования кода.