Signals
🔥 راهنمای کامل Angular Signals
Angular Signals یک سیستم مدیریت وضعیت (State Management) است که به فریمورک انگولار اجازه میدهد تغییرات داده در اپلیکیشن شما را به شکلی دقیق و بهینه ردیابی کند. این رویکرد جدید، مکانیزم Change Detection را متحول کرده و منجر به بهبود چشمگیر عملکرد میشود.
مفاهیم پایهای
سیستم Signals بر سه مفهوم اصلی استوار است که با هم کار میکنند تا یک سیستم Reactive قدرتمند را شکل دهند.
1. signal()
: Source of Truth
signal
یک "جعبه"
یا
wrapper
برای یک مقدار است که میتواند به مرور زمان تغییر کند. این جعبه به هر
consumer
که مقدار آن را میخواند، "اطلاع" میدهد.
WritableSignal<T>
: این نوعsignal
که با تابعsignal()
ساخته میشود، قابل نوشتن است.ReadonlySignal<T>
: این نوعsignal
فقط قابل خواندن است.computed
ها از این نوع هستند.
ایجاد و استفاده از
signal
:
برای ساختن یک
signal
Writable
، از تابع
signal()
با یک مقدار اولیه استفاده میکنیم.
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
standalone: true,
template: `
<p>Counter: {{ count() }}</p>
<button (click)="increment()">Increment</button>
<button (click)="reset()">Reset</button>
`
})
export class CounterComponent {
// ایجاد یک WritableSignal با مقدار اولیه 0
count = signal(0);
increment() {
// برای تغییر مقدار بر اساس مقدار قبلی
this.count.update(current => current + 1);
}
reset() {
// برای جایگزینی کامل مقدار
this.count.set(0);
}
}
متدهای اصلی WritableSignal
:
.set(value: T)
: مقدارsignal
را مستقیماً جایگزین میکند..update(updateFn: (value: T) => T)
: مقدارsignal
را بر اساس مقدار فعلی آن آپدیت میکند..asReadonly()
: یکReadonlySignal
ازsignal
فعلی برمیگرداند تا از تغییر آن در خارج از کلاس جلوگیری شود.
2. computed()
یک
computed
سیگنالی است که مقدار خود را از یک یا چند
signal
دیگر به دست میآورد. این
signal
ها فقط-خواندنی
(read-only)
و
lazy
هستند؛ یعنی فقط زمانی مقدارشان دوباره محاسبه میشود که یکی از وابستگیهایشان تغییر کرده باشد و کسی سعی در خواندن آنها داشته باشد.
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-user',
standalone: true,
template: `
<input (input)="firstName.set($any($event.target).value)" [value]="firstName()" />
<input (input)="lastName.set($any($event.target).value)" [value]="lastName()" />
<p>Full Name: {{ fullName() }}</p>
<p>{{ debugMessage() }}</p>
`
})
export class UserComponent {
firstName = signal('John');
lastName = signal('Doe');
// fullName یک computed signal است
fullName = computed(() => {
console.log('Calculating fullName...'); // این لاگ فقط زمان تغییر وابستگیها نمایش داده میشود
return `${this.firstName()} ${this.lastName()}`;
});
// مثالی دیگر از computed
debugMessage = computed(() => `First name has ${this.firstName().length} characters.`);
}
در این مثال،
fullName
فقط زمانی که
firstName
یا
lastName
تغییر کنند، دوباره محاسبه میشود، نه در هر بار رندر شدن کامپوننت.