Провайдеры и потребители

FAST Element предоставляет мощный механизм для организации обмена данными между компонентами через провайдеров (providers) и потребителей (consumers). Этот механизм позволяет создавать реактивные связи без явного прокидывания пропсов через цепочку компонентов, что упрощает архитектуру сложных приложений.


Основы провайдеров

Провайдер — это компонент или объект, который делает данные доступными для других компонентов. В FAST Element провайдер определяется с помощью декоратора @provides или функции provide. Основная задача провайдера — объявить значение и управлять его реактивностью.

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

import { FASTElement, customElement, observable, provides } from "@microsoft/fast-element";

@customElement({ name: "user-provider", template: `<slot></slot>` })
export class UserProvider extends FASTElement {
  @observable()
  @provides({ context: "user" })
  user = { name: "Alice", role: "admin" };
}
  • @observable делает значение реактивным, позволяя автоматически уведомлять всех потребителей при его изменении.
  • @provides({ context: "user" }) объявляет, что user доступен для компонентов, которые его потребляют.

Можно использовать динамическое предоставление значений, если требуется обновление состояния:

this.user = { name: "Bob", role: "editor" };

Все потребители автоматически получают обновленное значение.


Основы потребителей

Потребитель — компонент, который получает данные от провайдера через контекст. Для этого используется декоратор @consumes или функция consume.

Пример потребителя:

import { FASTElement, customElement, consumes, observable } from "@microsoft/fast-element";

@customElement({ name: "user-display", template: `<div>${x => x.user.name}</div>` })
export class UserDisplay extends FASTElement {
  @observable()
  @consumes({ context: "user" })
  user;
}
  • @consumes({ context: "user" }) связывает поле user с контекстом, предоставленным провайдером.
  • Любое изменение значения в провайдере автоматически обновляет user в потребителе.

Контекст и реактивность

FAST Element строит иерархию контекстов, в которой данные передаются сверху вниз через DOM. Если компонент-провайдер находится выше в дереве, все дочерние компоненты могут автоматически получать его данные. Контекст поддерживает реактивность, что делает его особенно полезным для глобальных состояний.

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

Связь нескольких уровней

Контекст в FAST Element работает через поиск вверх по DOM. Если провайдер находится выше на несколько уровней, потребитель всё равно его найдёт. Если несколько провайдеров предоставляют один контекст, будет использован ближайший сверху.

Пример:

<user-provider>
  <div>
    <user-display></user-display>
  </div>
</user-provider>

В этом случае user-display получит user от ближайшего родителя user-provider.


Динамическое управление контекстом

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

const provider = document.querySelector('user-provider');
provider.user = { name: "Charlie", role: "viewer" };

Все потребители, связанные с этим контекстом, мгновенно обновят отображение.


Ограничения и рекомендации

  1. Контекст работает только в пределах DOM-дерева. Компоненты, находящиеся вне этого дерева, не смогут потреблять данные.
  2. Изменения провайдера должны быть реактивными (@observable), иначе потребители не узнают об обновлении.
  3. Использование уникальных имён контекста предотвращает конфликты между различными провайдерами.
  4. Для сложных приложений можно создавать иерархии провайдеров, каждый из которых управляет отдельной областью состояния.

Применение провайдеров и потребителей

  • Глобальные настройки: цветовые темы, языковые локализации.
  • Состояния пользователя: авторизация, роли, данные профиля.
  • Общие сервисы: уведомления, кэш данных, веб-сокеты.
  • Модульные компоненты: компоненты могут быть изолированы, но при этом иметь доступ к общим данным без передачи через свойства.

Поддержка TypeScript

FAST Element полностью совместим с TypeScript. Для контекстов можно определить типы:

interface User {
  name: string;
  role: string;
}

@observable()
@provides({ context: "user" })
user: User;

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


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