سیگنال زاویه ای: مدیریت حالت واکنشی

Angular دائما در حال تکامل است و یکی از جدیدترین نوآوری هایی که به اکوسیستم معرفی شده است سیگنال. این ویژگی که از مفاهیم واکنش پذیری الهام گرفته شده است، نوید تغییر روشی را می دهد که توسعه دهندگان Angular با حالت های واکنشی و ارتباط بین کامپوننت ها برخورد می کنند.
ما آنچه را که سیگنال، چگونه کار می کند و چگونه می توان از آن برای عملکرد بیشتر برنامه های Angular و نگهداری آسان تر استفاده کرد.
چیست سیگنال انگولار نیست؟
آنها یک API واکنشی جدید هستند که در Angular معرفی شده اند که مدیریت داده و واکنش پذیری در برنامه ها را بر اساس الگویی به نام ساده می کند. الگوی طراحی ناظر. با توجه به این الگو داریم یک ناشر که مقداری مقدار را به همراه فهرستی از مشترکین کسانی که به آن علاقه مند هستند، و هنگامی که مقدار تغییر می کند، یک اعلان دریافت می کنند.
در اصل، سیگنال:
- یک مقدار واکنشی را ذخیره می کند.
- هنگامی که مقدار تغییر می کند به طور خودکار به مصرف کنندگان اطلاع می دهد.
- نوشتن کد واکنشی را آسان تر می کند.
چرا استفاده کنید سیگنال ها انگولار نیست؟
-
Simplicity: آنها ایجاد حالت های واکنشی را ساده می کنند. در مقایسه با قابل مشاهده انجام دهید RxJS، به کد کمتری برای پیکربندی نیاز دارند و برای مبتدیان Angular بصری تر هستند.
-
عملکرد: بهروزرسانیها و نماهای حالت را بهینه کنید. فقط اجزایی که مستقیماً به a وابسته هستند سیگنال به روز می شوند و از رندرهای غیر ضروری اجتناب می شود.
-
وابستگی های کمتر: به آن وابسته نباشید RxJS برای سناریوهای اساسی این منحنی یادگیری را کاهش می دهد و انتقال به Angular را آسان تر می کند.
-
مقیاس پذیری: برای کارکرد کامل در معماری های پیچیده طراحی شده اند.
چگونه در Angular کار می کنند؟
Os سیگنال ها در Angular سه مفهوم اصلی وجود دارد:
-
ایجاد سیگنال ها: شما یک را ایجاد می کنید سیگنال برای ذخیره یک مقدار واکنشی
-
خواندن سیگنال ها: می توانید به مقدار دسترسی داشته باشید سیگنال مستقیما
-
به روز رسانی از سیگنال ها: می توانید مقدار را تغییر دهید و به مصرف کنندگان اطلاع دهید.
دستمان را کثیف کنیم!
برای تغییر مقدار سیگنال.
- اولی توسط مجموعه که تعریف می کند سیگنال به یک مقدار جدید؛
app.component.html
Nosso Signal: {{exemploSignal()}}
app.component.ts
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RouterOutlet,
],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'exemplos';
protected exemploSignal = signal('angular');
constructor() {
}
executar(){
this.exemploSignal.set('Framework Angular');
}
}
- دومی توسط به روز رسانی کنید که بر اساس مقدار فعلی تنظیم می شود.
app.component.html
Nosso Signal: {{exemploCount()}}
app.component.ts
import { Component, signal } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RouterOutlet,
],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'exemplos';
protected exemploCount = signal(1);
constructor() {
}
executar(){
this.exemploCount.update(atual => atual + 1);
}
}
1 – مثال شمارنده
برای مثال اول، یک شمارنده بسیار ساده برای آزمایش دانش ایجاد خواهیم کرد.
contador.component.html
class="container">
Contador: {{ contador() }}
contador.component.css
:host {
display: block;
}
.container {
display: flex;
gap: 10px;
}
contador.component.ts
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-contador',
standalone: true,
imports: [],
templateUrl: './contador.component.html',
styleUrl: './contador.component.css'
})
export class ContadorComponent {
contador = signal(0);
incrementar(){
this.contador.update(valor => valor + 1);
}
decrementar(){
this.contador.update(valor => valor - 1);
}
limpar(){
this.contador.set(0);
}
}
چه بازی در این کد، در حال حاضر وجود دارد سیگنال که یک مقدار اولیه به خط اضافه می کنیم:
contador = signal(0);
در توابع افزایش و کاهش از تابع استفاده می کنیم به روز رسانی کنید انجام دهید سیگنال قابل نوشتن برای گرفتن مقدار قبلی و افزایش یا کاهش یک مقدار جدید.
incrementar(){
this.contador.update(valor => valor + 1);
}
decrementar(){
this.contador.update(valor => valor - 1);
}
برای تمیز کردن استفاده شد، تابع مجموعه برای اضافه کردن یک مقدار جدید اما بدون در نظر گرفتن مقدار قبلی.
حال چگونه می توانیم از به روز رسانی ارزش در html استفاده کنیم؟ بسیار ساده است که مقدار تغییر یافته را در نما نشان دهید و فقط آن را به عنوان “عملکرد” صدا کنید.
Contador: {{ contador() }}
2 – سیگنال های محاسبه شده
سیگنال ها محاسبه شده اند سیگنال ها فقط خواندنی که ارزش خود را از دیگران می گیرند سیگنال ها. تو تعریف کن سیگنال ها با استفاده از تابع محاسبه می شود محاسبه شده است و مشخص کردن یک مشتق:
contador = signal(0);
contadorVezesDois: Signal<number> = computed(() => this.contador() * 2);
در مثال ما، زمانی که مقدار کنتادور به روز می شود accountantTimesTwo تغییر خواهد کرد زیرا بستگی به آن دارد کنتادور.
o کد کامل:
contador-v2.component.html
class="container">
Contador: {{ contador() }}
class="result">
Valor do contador vezes 2: {{ contadorVezesDois() }}
contador-v2.component.css
:host {
display: block;
}
.container {
display: flex;
gap: 10px;
}
.result{
margin-top: 10px;
}
counter-v2.component.ts
import { Component, computed, Signal, signal } from '@angular/core';
@Component({
selector: 'app-contador-v2',
standalone: true,
imports: [],
templateUrl: './contador-v2.component.html',
styleUrl: './contador-v2.component.css'
})
export class ContadorV2Component {
contador = signal(0);
contadorVezesDois: Signal<number> = computed(() => this.contador() * 2);
incrementar(){
this.contador.update(valor => valor + 1);
}
decrementar(){
this.contador.update(valor => valor - 1);
}
limpar(){
this.contador.set(0);
}
}
3 – جلوه ها
سیگنال مصرف کنندگان علاقه مند را هنگام تغییر مطلع کنید. اثر عملیاتی است که هر زمان یک یا چند مقدار از آن انجام می شود سیگنال تغییر دهید.
برای این مثال، اجازه دهید یک سرویس ایجاد کنیم ریشه.
import { Injectable, signal } from "@angular/core";
@Injectable({ providedIn: 'root' })
export class Store {
contador = signal(0);
incrementar(){
this.contador.update(valor => valor + 1);
}
decrementar(){
this.contador.update(valor => valor - 1);
}
limpar(){
this.contador.set(0);
}
}
مولفه شمارنده اکنون به این شکل خواهد بود.
contador-v3.component.html
class="container">
Contador: {{ store.contador() }}
contador-v3.component.css
:host {
display: block;
}
.container {
display: flex;
gap: 10px;
}
.result{
margin-top: 10px;
}
counter-v3.component.ts
import { Component, inject } from '@angular/core';
import { Store } from '../store';
@Component({
selector: 'app-contador-v3',
standalone: true,
imports: [],
templateUrl: './contador-v3.component.html',
styleUrl: './contador-v3.component.css'
})
export class ContadorV3Component {
protected store = inject(Store);
}
در حال حاضر app.component، ما داریم اثر.
import { Component, effect, inject } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ContadorV3Component } from './contador-v3/contador-v3.component';
import { Store } from './store';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RouterOutlet,
ContadorV3Component,
],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
protected store = inject(Store)
constructor() {
effect(() => {
const contador = this.store.contador();
if(contador < 0) {
console.log('Negativo')
}
else{
const par = contador % 2 === 0;
if(par) {
console.log('Par')
} else {
console.log('Impar')
}
}
});
}
}
بنابراین زمانی که افزایش، کاهش یا پاک شدن به اطلاع می رسد اثر، جایی که من یک پرینت کنسول ساده انجام دادم.
- اثر حداقل یک بار فعال خواهد شد.
- اثر حداقل پس از یکی از آن ها فعال می شود سیگنال که به تغییر آن بستگی دارد (مقدار آن را می خواند).
- اثر حداقل تعداد دفعات فراخوانی خواهد شد. این بدان معناست که اگر چندین سیگنال ها که از آن اثر بستگی به تغییر مقادیر آنها در همان زمان دارد، کد فقط یک بار اجرا می شود.
4 – روی Push Compooent
Angular فقط زمانی تغییرات را بررسی میکند ورودی تغییر می کند یا رویدادی راه اندازی می شود. بنابراین اگر جزء شما استفاده می کند changeDetection: ChangeDetectionStrategy.OnPush، تغییرات فقط در DOM موارد ذکر شده توسط ما
در مثال اول، یک ویژگی به نام ایجاد می کنیم شجاعت و یک تایمر در سازنده قرار دهید که افزایش می یابد. حتی با افزایش در شجاعت روی نمایشگر روشن تأثیر نمی گذارد DOM.
on-push-teste.component.ts
import { ChangeDetectionStrategy, Component, signal } from "@angular/core";
@Component({
selector: 'app-on-push-teste',
standalone: true,
template: `
O valor é: {{valor}}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnPushTesteComponent {
valor = 1;
constructor(){
setInterval(() => {
this.valor++;
console.log('Mudou o valor: ', this.valor);
}, 1000);
}
}
کنسول در حال افزایش است:
صفحه نمایش تغییر نمی کند:
با این حال، زمانی که ما استفاده می کنیم سیگنال رفتار کاملا متفاوت است، به شرح زیر است:
on-push-teste.component.ts
import { ChangeDetectionStrategy, Component, signal } from "@angular/core";
@Component({
selector: 'app-on-push-teste',
standalone: true,
template: `
O valor é: {{valor()}}
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class OnPushTesteComponent {
valor = signal(1);
constructor(){
setInterval(() => {
this.valor.update(valor => valor + 1);
console.log('Mudou o valor: ', this.valor());
}, 1000);
}
}
اکنون صفحه مقدار افزایش یافته است:
app.component.html
app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { OnPushTesteComponent } from './on-push-teste/on-push-teste.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [
RouterOutlet,
OnPushTesteComponent
],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
constructor() {
}
}
چرا این اتفاق می افتد؟ اکنون چگونه آن را تعریف کنیم
ts valor = signal(1);
به عنوان سیگنال، هر تغییری در آن نشان می دهد که مقدار جدید باید ارائه شود.
کد کامل: Github
مرجع:
سیگنال های زاویه ای