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

Lit — это современный фреймворк для создания веб-компонентов на основе стандартов Web Components. Эффективная передача данных между компонентами является одной из ключевых задач при построении сложных интерфейсов. В Lit это реализуется через свойства (properties), атрибуты (attributes), события (events) и контекст (context).


Свойства и атрибуты

В Lit компонент может иметь свойства, которые автоматически синхронизируются с его шаблоном. Объявление свойства осуществляется с помощью декоратора @property:

import { LitElement, html } from 'lit';
import { property } from 'lit/decorators.js';

class UserCard extends LitElement {
  @property({ type: String }) name = '';
  @property({ type: Number }) age = 0;

  render() {
    return html`<p>${this.name}, ${this.age} лет</p>`;
  }
}

customElements.define('user-card', UserCard);

Свойства могут быть связаны с атрибутами HTML, что позволяет передавать данные через разметку:

<user-card name="Иван" age="30"></user-card>

Важно: все свойства, синхронизированные с атрибутами, автоматически конвертируются в указанный тип (String, Number, Boolean, Array, Object) через механизм Lit.


Двусторонняя связь и реактивность

Lit обеспечивает реактивность компонентов. Любое изменение свойства вызывает обновление шаблона. Для передачи данных от родителя к дочернему компоненту используется простая установка значения свойства:

const userCard = document.querySelector('user-card');
userCard.name = 'Мария';
userCard.age = 25;

После этого render перерисует компонент, отражая новые данные.


Передача данных через события

Для передачи данных от дочернего компонента к родительскому используется механизм кастомных событий:

class CounterButton extends LitElement {
  @property({ type: Number }) count = 0;

  increment() {
    this.count++;
    this.dispatchEvent(new CustomEvent('count-changed', {
      detail: { count: this.count },
      bubbles: true,
      composed: true
    }));
  }

  render() {
    return html`<button @click=${this.increment}>${this.count}</button>`;
  }
}

customElements.define('counter-button', CounterButton);

Родительский компонент может слушать событие и обновлять свои данные:

<counter-button id="counter"></counter-button>
<script>
  const counter = document.getElementById('counter');
  counter.addEventListener('count-changed', (e) => {
    console.log('Новый счет:', e.detail.count);
  });
</script>

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

  • bubbles: true позволяет событию всплывать вверх по DOM.
  • composed: true позволяет событию проходить через Shadow DOM границы.

Использование слотов для передачи контента

Слоты позволяют компонентам принимать вложенный контент:

class CardComponent extends LitElement {
  render() {
    return html`
      <div class="card">
        <slot></slot>
      </div>
    `;
  }
}

customElements.define('card-component', CardComponent);

Вложенный контент передается через разметку:

<card-component>
  <p>Контент внутри карточки</p>
</card-component>

Слоты хорошо подходят для передачи не данных, а структурного контента.


Связь через контекст и провайдеры

Для сложных приложений с глубокой иерархией компонентов использование контекста упрощает передачу данных без явной проброски через каждый компонент. В Lit применяются специальные API, такие как @contextProvider и @contextConsumer (из lit-context или аналогичных библиотек).

Пример предоставления и потребления контекста:

import { contextProvider, contextConsumer } from '@lit-labs/context';
import { createContext } from '@lit-labs/context';

const ThemeContext = createContext('theme');

class ThemeProvider extends LitElement {
  @contextProvider({ context: ThemeContext })
  theme = 'dark';

  render() {
    return html`<slot></slot>`;
  }
}

class ThemedButton extends LitElement {
  @contextConsumer({ context: ThemeContext })
  theme;

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

Контекст позволяет избежать “проброса” данных через каждый уровень DOM, сохраняя реактивность.


Резюме по методам передачи данных

  1. Свойства и атрибуты — прямое управление данными компонента.
  2. События — обратная связь от дочернего компонента к родительскому.
  3. Слоты — передача структурного контента.
  4. Контекст — передача глобальных данных без вложенных пропов.

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


Эта система передачи данных делает Lit мощным инструментом для построения сложных, реактивных веб-компонентов с чистой и понятной архитектурой.