تشخیص تغییر (Change Detection)
تشخیص تغییر انگولار یعنی تازه کردن نما وقتی حالت عوض می شود. «حالت (State)» همان داده زنده صفحه است. با «سیگنال (Signal)» تغییرها واضح و قابل پیش بینی می شوند. همچنین با «OnPush» فقط در موقعیت های لازم بررسی انجام می شود. پس رندر سریع تر می ماند.
مبانی تشخیص تغییر
حالت را واضح تغییر بده تا نما به موقع آپدیت شود. سپس از OnPush برای بررسی های کم تر استفاده کن. همچنین برای لیست ها، «هویت پایدار» بده تا DOM دوباره ساخته نشود.
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, signal } from '@angular/core';
@Component({
selector: 'demo-onpush',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: ``,
})
export class DemoComponent {
items = signal([{ id: 1, label: 'A' }]);
add() {
this.items.update(a => [
...a,
{ id: Date.now(), label: 'N' },
]);
}
}
// Template idea:
// @for (it of items(); track it.id) { <li>{{ it.label }}</li> }
OnPush و Signals
OnPush یعنی فقط هنگام ورودی ها، رخدادها، کارهای ناهمگام، و سیگنال ها بررسی انجام شود. بنابراین خرج رندر کم می شود. سپس سیگنال ها هم تغییرها را «هل می دهند».
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, signal } from '@angular/core';
@Component({
selector: 'app-onpush-signals',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: ``,
})
export class AppOnPushSignalsComponent {
count = signal(0);
inc() {
this.count.set(this.count() + 1);
}
}
نمونه عملی OnPush + Signals
در این نمونه، با سیگنال ها مقدار می سازیم. سپس OnPush فقط هنگام تغییرهای لازم رندر می کند. همچنین لیست با track پایدار می ماند.
import { bootstrapApplication } from '@angular/platform-browser';
import { Component } from '@angular/core';
import { signal } from '@angular/core';
import { ChangeDetectionStrategy } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule],
template: `
<h3>OnPush + Signals</h3>
<p>Count: {{ count() }}</p>
<button (click)=\"inc()\">Increment</button>
<ul>
@for (it of items(); track it.id) {
<li>{{ it.label }}</li>
} @empty {
<li>Empty</li>
}
</ul>
`,
})
export class AppComponent {
count = signal(0);
items = signal([
{ id: 1, label: 'A' },
{ id: 2, label: 'B' },
]);
inc() {
this.count.set(this.count() + 1);
}
}
bootstrapApplication(AppComponent);
الگوهای سیگنال برای کارایی
«مشتق (Computed)» یعنی مقدار فقط خواندنی از ورودی ها. همچنین «افکت (Effect)» یعنی کار جانبی هنگام تغییر. این دو را کوچک و ساده نگه دار.
import { signal, computed, effect } from '@angular/core';
const count = signal(0);
const double = computed(() => count() * 2);
effect(() => console.log('double =', double()));
لیست پایدار با track
برای لیست ها از track با کلید یکتا استفاده کن. بنابراین DOM حفظ می شود و دوباره سازی کم می شود.
@for (it of items(); track it.id) {
<li>{{ it.label }}</li>
}
گام های عملی
- حالت را با سیگنال بساز.
- کامپوننت را OnPush کن.
- برای لیست ها، track با کلید یکتا بده.
- افکت ها را کوچک و ساده نگه دار.
نکته: تغییرات را «نامتغیر» انجام بده. یعنی آرایه یا شیء جدید بساز. سپس OnPush سریع و قابل پیش بینی می ماند.
جمع بندی سریع
- OnPush بررسی ها را کم می کند.
- سیگنال ها تغییر را هل می دهند.
- track لیست را پایدار نگه می دارد.
- computed و effect ساده باشند.
بیشتر بخوان: تشخیص تغییر انگولار، سیگنال ها در انگولار، و کنترل جریان.