Модернізація компонентів Angular: Сигнали, Inputs, Outputs та обов’язкові запити в Angular 17+

pic

Вступ

Angular продовжує еволюціонувати за допомогою API на основі сигналів, що вводять чистіший, декларативний та реактивний підхід до побудови компонентів. У Angular 17+ сигнали замінюють традиційні декоратори, такі як @Input, @Output, @ViewChild та @ViewChildren, одночасно надаючи нові можливості, такі як обов'язкові запити та динамічні трансформації.

Цей пост занурюється глибше в ці нововведення, демонструючи практичні приклади того, що відкривають сигнали, чого не можуть досягти традиційні декоратори, а також як вони спрощують комунікацію компонентів, запити до DOM і гарантії під час виконання.

1. Сигнали в Inputs і Outputs

Сигнали з @Input

Функція input() покращує комунікацію компонентів, роблячи введення реактивним, підтримуючи трансформації та забезпечуючи необхідні значення. Це усуває потребу в ручному виявленні змін (ngOnChanges) або додатковій логіці.

Приклад: Реактивне введення з трансформацією

import { Component, input } from '@angular/core';  

@Component({  
 selector: 'app-transformed-input',  
 template: `
Formatted Input: {{ formattedValue() }}
`   })   
export class TransformedInputComponent {    
 formattedValue = input('', { transform: (value: string) => value.trim().toUpperCase() });   
} 

Що дають сигнали:
Реактивний доступ: Використовуйте formattedValue() для отримання поточного значення.
Трансформації: Обробка вхідних даних (наприклад, обрізання, форматування) до того, як вони будуть використані в компоненті.

Використання обов'язкових параметрів з Inputs

Переконайтеся, що важливі входи завжди надаються за допомогою параметра required:

import { Component, input } from '@angular/core';  

@Component({    
 selector: 'app-required-input',    
 template: `
Required Input: {{ requiredValue() }}
`   
})   
export class RequiredInputComponent {    
 requiredValue = input('', { required: true });   
} 

Що дають сигнали:
- Angular викине помилку під час виконання, якщо батьківський компонент не надасть вхідне значення:

Error: Required input 'requiredValue' is missing for component RequiredInputComponent.

Сигнали з @Output

Функція output() спрощує емітери подій, безпосередньо інтегруючи сигнали в систему виведення.

Приклад: Вихід на основі сигналу

import { Component, output } from '@angular/core';  

@Component({    
 selector: 'app-custom-button',    
 template: `Click Me`   
})   
export class CustomButtonComponent {    
 action = output();       
 notify() {    
 this.action.emit('Button clicked!');    
 }   
} 

Що дають сигнали:
- Безпека типів: Забезпечує, щоб емітовані події відповідали очікуваному типу.
- Спрощений синтаксис: Більше не потрібно використовувати EventEmitter.

Сигнали в запитах до компонентів

Заміняючи @ViewChild та @ViewChildren

Запити на основі сигналів, як-от viewChild() і viewChildren(), роблять доступ до DOM або дочірніх компонентів реактивним, усуваючи потребу в ручних перевірках на null або синхронізації з життєвим циклом.

Приклад: Заміняючи @ViewChild

import { Component, viewChild, ElementRef } from '@angular/core';  

@Component({  
 selector: 'app-input-focus',  
 template: ``  
})  
export class InputFocusComponent {  
 focusInput = viewChild('focusInput');  

 ngAfterViewInit() {  
 this.focusInput().focus(); // Реактивний доступ до елементу DOM  
 }  
}

Приклад: Заміняючи @ViewChildren

import { Component, viewChildren } from '@angular/core';  
import { ItemComponent } from './item.component';  

@Component({  
 selector: 'app-items',  
 template: ``  
})  
export class ItemsComponent {  
 items = ['Item 1', 'Item 2', 'Item 3'];  
 itemComponents = viewChildren(ItemComponent);  

 ngAfterViewInit() {  
 console.log(this.itemComponents().length); // Логує кількість екземплярів ItemComponent  
 }  
}

Обов'язкові запити

Обов'язкові запити забезпечують, що певні дочірні компоненти або елементи DOM повинні існувати в шаблоні, додаючи гарантії під час виконання і усуваючи логіку перевірки на null.

Приклад: Обов'язкові запити до компонентів

import { Component, viewChild, contentChild } from '@angular/core';  

@Component({  
 selector: 'app-custom-card',  
 template: `  

    `  
})   
export class CustomCard {    
 header = viewChild.required(CustomCardHeader); // Обов'язковий запит    
 body = contentChild(CustomCardBody); // Необов'язковий запит   
} 

3. Що дають сигнали, чого не можуть традиційні декоратори

pic

4. Приклад: Ланцюжкові обчислювані сигнали

import { Component, signal, computed } from '@angular/core';  

@Component({  
 selector: 'app-price-calculator',  
 template: `
Total Price: {{ totalPrice() }}
`   
})   
export class PriceCalculatorComponent {    
 quantity = signal(2);    
 pricePerUnit = signal(50);    
 totalPrice = computed(() => this.quantity() * this.pricePerUnit());   
} 

Що дають сигнали:
• Реактивні, динамічні похідні значення, які автоматично оновлюються при зміні залежностей.

Чому традиційні декоратори не вистачає:
Потрібні методи або хуки життєвого циклу для похідного стану:

@Input() quantity = 2;  
@Input() pricePerUnit = 50;  
totalPrice!: number;  

ngOnChanges() {  
 this.totalPrice = this.quantity * this.pricePerUnit;  
} 

Висновок

API на основі сигналів в Angular відкриває ряд можливостей, які роблять компоненти більш декларативними, реактивними та безпечними за типами. Від забезпечення обов'язкових введень і запитів до дозволу на динамічні виводи та обчислений стан, ці нововведення покращують зрозумілість коду, безпеку під час виконання та продуктивність.

Заклик до дії:
"Яка функція, що працює лише з сигналами, вам найбільше подобається? Поділіться своїми думками та досвідом у коментарях!"

Перекладено з: Modernizing Angular Components: Signals, Inputs, Outputs, and Required Queries in Angular 17+

Leave a Reply

Your email address will not be published. Required fields are marked *