Анатомия компонента

Stencil — это современный фреймворк для создания веб-компонентов, который позволяет разработчикам легко создавать повторно используемые элементы для интерфейсов. В отличие от традиционных фреймворков, таких как React или Angular, Stencil ориентирован на использование стандартов веб-компонентов, что позволяет интегрировать компоненты в проекты с различными технологическими стеками.

Каждый компонент в Stencil состоит из нескольких ключевых элементов: интерфейса, логики, стилей и тестов. Все эти части объединяются в единую структуру, которая помогает создавать функциональные и производительные компоненты.

Основные элементы компонента

  1. Классовая структура Каждый компонент в Stencil представляет собой класс, который наследуется от базового класса Component. Этот класс содержит методы, описывающие поведение компонента, а также ссылки на его состояние и интерфейс.

  2. Декораторы Stencil использует декораторы для аннотирования классов и их методов. Наиболее важным декоратором является @Component(), который описывает сам компонент. Декораторы также используются для работы с пропсами, состоянием, событиями и жизненным циклом компонента.

  3. Рендеринг шаблона В Stencil шаблон компонента пишется с использованием JSX — синтаксиса, который похож на HTML, но позволяет вставлять логику JavaScript. JSX компилируется в JavaScript, что даёт разработчикам возможность динамически изменять DOM в зависимости от состояния компонента.

Классовая структура

Каждый компонент в Stencil — это класс, который определяет его поведение и внешний вид. Структура этого класса основывается на JavaScript классе и декораторе @Component().

Пример компонента:

import { Component, h } from '@stencil/core';

@Component({
  tag: 'my-component',
  styleUrl: 'my-component.css',
  shadow: true,
})
export class MyComponent {
  render() {
    return <div>Hello, World!</div>;
  }
}

Описание полей компонента:

  • tag: строка, которая определяет имя тега компонента в HTML.
  • styleUrl: путь к файлу стилей, который будет использоваться в компоненте.
  • shadow: флаг, который включает или отключает Shadow DOM для компонента. Это позволяет изолировать стили и структуру компонента от остальной части приложения.

Декораторы

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

  1. @Component() — используется для объявления компонента. В декораторе указываются параметры, такие как имя тега, путь к стилям и необходимость использования Shadow DOM.

  2. @Prop() — используется для объявления входных параметров компонента, которые могут быть установлены извне.

  3. @State() — используется для создания локальных состояний, которые влияют на рендеринг компонента.

  4. @Event() — используется для объявления событий, которые компонент может генерировать и которые могут быть обработаны родительским элементом.

Пример компонента с пропсами, состоянием и событиями:

import { Component, h, Prop, State, Event, EventEmitter } from '@stencil/core';

@Component({
  tag: 'counter-component',
  styleUrl: 'counter-component.css',
  shadow: true,
})
export class CounterComponent {
  @Prop() initialCount: number = 0;
  @State() count: number = this.initialCount;
  @Event() countChanged: EventEmitter;

  increment() {
    this.count++;
    this.countChanged.emit(this.count);
  }

  render() {
    return (
      <div>
        <button onCl ick={() => this.increment()}>Increment</button>
        <p>Current count: {this.count}</p>
      </div>
    );
  }
}

В этом примере:

  • @Prop() используется для получения значения свойства initialCount, которое можно задать при использовании компонента.
  • @State() хранит текущее состояние счётчика, которое обновляется при нажатии на кнопку.
  • @Event() создаёт событие countChanged, которое срабатывает при каждом изменении значения счётчика.

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

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

  1. componentWillLoad() — вызывается перед тем, как компонент будет загружен и отрендерен. Здесь можно выполнять асинхронные операции, такие как загрузка данных.

  2. componentDidLoad() — вызывается после того, как компонент был загружен и отрендерен.

  3. componentWillUpdate() — вызывается перед тем, как компонент будет обновлён, например, при изменении его состояния или пропсов.

  4. componentDidUpdate() — вызывается после того, как компонент был обновлён.

  5. componentWillUnload() — вызывается перед тем, как компонент будет удалён.

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

import { Component, h, State } from '@stencil/core';

@Component({
  tag: 'lifecycle-demo',
  styleUrl: 'lifecycle-demo.css',
  shadow: true,
})
export class LifecycleDemo {
  @State() data: string = '';

  componentWillLoad() {
    console.log('Component will load');
  }

  componentDidLoad() {
    console.log('Component did load');
  }

  componentWillUpdate() {
    console.log('Component will update');
  }

  componentDidUpdate() {
    console.log('Component did update');
  }

  componentWillUnload() {
    console.log('Component will unload');
  }

  render() {
    return <div>{this.data}</div>;
  }
}

Работа с состоянием

Состояние компонента в Stencil хранится с помощью декоратора @State(). Эти значения автоматически отслеживаются фреймворком, и компоненты перерисовываются, когда состояние изменяется.

Важно отметить, что изменения состояния происходят асинхронно, а обновление компонента не происходит немедленно, что помогает избежать лишних перерисовок.

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

import { Component, h, State } from '@stencil/core';

@Component({
  tag: 'state-demo',
  styleUrl: 'state-demo.css',
  shadow: true,
})
export class StateDemo {
  @State() count: number = 0;

  increment() {
    this.count++;
  }

  render() {
    return (
      <div>
        <p>Current count: {this.count}</p>
        <button onCl ick={() => this.increment()}>Increment</button>
      </div>
    );
  }
}

Пропсы и события

Stencil позволяет компоновать интерфейсы с помощью пропсов и событий, что даёт гибкость в использовании и взаимодействии компонентов.

  • Пропсы: позволяют передавать значения в компоненты извне. Они должны быть обязательно указаны через декоратор @Prop().
  • События: позволяют компонентам передавать данные или уведомлять родительские элементы о произошедших изменениях. Для создания событий используется декоратор @Event().

Пример компонента с пропсами и событиями:

import { Component, h, Prop, Event, EventEmitter } from '@stencil/core';

@Component({
  tag: 'user-card',
  styleUrl: 'user-card.css',
  shadow: true,
})
export class UserCard {
  @Prop() name: string;
  @Prop() age: number;
  @Event() userClicked: EventEmitter;

  handleClick() {
    this.userClicked.emit({ name: this.name, age: this.age });
  }

  render() {
    return (
      <div onCl ick={() => this.handleClick()}>
        <p>Name: {this.name}</p>
        <p>Age: {this.age}</p>
      </div>
    );
  }
}

В этом примере компонент UserCard принимает два пропса: name и age, а также генерирует событие userClicked, которое передает информацию о пользователе.

Заключение

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