В Stencil, как и в других современных фреймворках, компоненты являются основой архитектуры приложения. Один из ключевых аспектов работы с компонентами — это использование props (свойств), которые позволяют передавать данные из родительского компонента в дочерний. В этом разделе будет рассмотрено, как эффективно использовать props в Stencil.
Props — это параметры, которые компонент принимает от своего родителя. Это позволяет делать компоненты динамическими и многократно переиспользуемыми, так как можно подставлять разные данные в зависимости от контекста использования компонента.
Stencil поддерживает строгую типизацию свойств компонентов, что позволяет избежать многих ошибок на этапе разработки и улучшает автодополнение в IDE. Для задания типа свойства используется синтаксис TypeScript.
Пример объявления props с типами:
import { Component, Prop, h } from '@stencil/core';
@Component({
tag: 'user-profile',
styleUrl: 'user-profile.css',
shadow: true,
})
export class UserProfile {
@Prop() name: string;
@Prop() age: number;
render() {
return (
<div>
<h1>{this.name}</h1>
<p>Возраст: {this.age}</p>
</div>
);
}
}
Здесь компоненты name и age имеют типы
string и number соответственно. TypeScript
гарантирует, что передаваемые значения будут соответствовать указанным
типам.
В Stencil можно задавать, какие props являются обязательными, а какие
— нет. Для обязательных свойств используется декоратор
@Prop(), а для необязательных —
@Prop() optional.
Пример обязательного и необязательного prop:
@Component({
tag: 'app-card',
styleUrl: 'app-card.css',
shadow: true,
})
export class AppCard {
@Prop() title: string;
@Prop() description?: string; // Необязательное свойство
render() {
return (
<div class="card">
<h2>{this.title}</h2>
{this.description && <p>{this.description}</p>}
</div>
);
}
}
Здесь свойство title обязательно, а
description является необязательным, что означает, что его
можно не передавать при использовании компонента.
Props могут иметь значения по умолчанию. Это особенно полезно, когда требуется, чтобы свойство компонента было задано не обязательно, но при этом имело значение, если оно не передано. В Stencil для этого используют специальный синтаксис, где в свойстве присваивается значение по умолчанию.
Пример с значением по умолчанию:
@Component({
tag: 'app-button',
styleUrl: 'app-button.css',
shadow: true,
})
export class AppButton {
@Prop() label: string = 'Кнопка';
render() {
return (
<button>{this.label}</button>
);
}
}
Если родительский компонент не передаст значение для
label, то по умолчанию будет использовано значение
'Кнопка'.
Props, как правило, являются read-only (только для чтения) для компонентов. Это означает, что после того как свойство было передано компоненту, оно не должно изменяться внутри компонента. Если требуется обновить значение свойства, следует использовать внутреннее состояние (state) компонента.
Пример:
@Component({
tag: 'counter',
styleUrl: 'counter.css',
shadow: true,
})
export class Counter {
@Prop() initialCount: number;
@State() count: number;
componentWillLoad() {
this.count = this.initialCount;
}
increment() {
this.count++;
}
render() {
return (
<div>
<p>Счёт: {this.count}</p>
<button onCl ick={() => this.increment()}>Увеличить</button>
</div>
);
}
}
Здесь свойство initialCount передается родителем, но
фактическое состояние компонента хранится в переменной
count, которое можно изменять внутри компонента.
Stencil автоматически отслеживает изменения props и вызывает перерендер компонента, если значение одного из них изменилось. Это делает работу с props прозрачной и простой, так как компоненты автоматически обновляются в ответ на изменение данных.
Пример динамического обновления:
@Component({
tag: 'app-toggle',
styleUrl: 'app-toggle.css',
shadow: true,
})
export class AppToggle {
@Prop() isOn: boolean;
render() {
return (
<div>
<p>Состояние: {this.isOn ? 'Включено' : 'Выключено'}</p>
</div>
);
}
}
Если значение isOn изменится в родительском компоненте,
то Stencil автоматически отрендерит компонент с новым значением, не
требуя дополнительного вмешательства.
Props могут быть не только примитивами (строки, числа и булевы значения), но и более сложными типами, такими как объекты и массивы. В Stencil можно передавать такие типы, но важно понимать, что любые изменения объекта или массива внутри компонента не приведут к обновлению рендеринга, если сами эти данные не были изменены (например, ссылка на объект не поменялась).
Пример с объектом:
@Component({
tag: 'user-card',
styleUrl: 'user-card.css',
shadow: true,
})
export class UserCard {
@Prop() userInfo: { name: string; age: number };
render() {
return (
<div>
<h2>{this.userInfo.name}</h2>
<p>Возраст: {this.userInfo.age}</p>
</div>
);
}
}
В данном случае объект userInfo передается как prop, и
Stencil будет следить за изменениями только в случае, если объект будет
заменён полностью (например, через новый объект).
Stencil предоставляет декоратор @Watch, который
позволяет отслеживать изменения значений props и реагировать на них с
помощью методов жизненного цикла компонента. Это полезно, если
необходимо выполнить дополнительные действия или логику при изменении
свойства.
Пример использования @Watch:
@Component({
tag: 'app-lifecycle',
styleUrl: 'app-lifecycle.css',
shadow: true,
})
export class AppLifecycle {
@Prop() count: number;
@Watch('count')
countChanged(newValue: number, oldValue: number) {
console.log(`Счёт изменился с ${oldValue} на ${newValue}`);
}
render() {
return <p>Текущий счёт: {this.count}</p>;
}
}
В этом примере метод countChanged будет вызван каждый
раз, когда значение count изменяется.
Props в Stencil являются мощным инструментом для создания динамичных и переиспользуемых компонентов. С помощью строгой типизации и декораторов можно легко управлять данными, передаваемыми между компонентами, и следить за их изменениями. Stencil обеспечивает удобный и предсказуемый механизм для работы с props, который идеально подходит для создания сложных веб-приложений с высокой степенью модульности.