Açısal Rönesans Bölüm 2: Sinyallerle reaktif programlama

Saberie

Active member
Bu yazı serisinin ilk kısmı hidrasyon ve sunucu tarafı oluşturma hakkındaydı, şimdi sinyallerden bahsediyoruz. Angular'daki sinyal entegrasyonu 17 serisi boyunca devam etti. Sürüm 17.1, 17.2 ve 17.3 daha sonra bu makalede açıklanan yeni özellikleri tanıttı. Sinyaller muhtemelen en dikkat çekici özelliktir ve haklı olarak da öyle.

Duyuru








Rainer Hahnekamp, AngularArchitects.io uzman ağının eğitmeni ve danışmanıdır ve Angular'ın tüm yönleriyle ilgili eğitimlerden sorumludur. Ayrıca YouTube'daki ng-news ile haftalık olarak Angular ortamındaki ilgili etkinliklere kısa bir genel bakış sağlar.








Hızlandırılmış rota sinyalleri


Sinyaller zaten sürüm 16'da çerçeveye dahil edilmişti ancak o sırada hala geliştirici önizleme durumundaydı. Sinyal kavramı, ön uç çerçevelerin DOM'u nerede güncellemeleri gerektiğini nasıl anladıklarına yönelik yeni bir yaklaşımdır. Angular'da odak noktası her zaman bileşen ağacıydı ancak artık sinyaller bu durumu değiştiriyor.

Sinyallerin uygulanması temel olarak üç yöntemden oluşur: signal(), computed() VE effect(). Bunlar reaktif yapılardır. computed() VE effect() bir veya daha fazla sinyale bağımlılık yaratabilir. Değer üreten sinyaller üretici görevi görür. Üreticiye bağlı olan sinyaller tüketicilerdir. Bir sinyalin hem üretici hem de tüketici olması da mümkündür. Bu, bir uygulamanın tüm durumunun bir sinyal grafiğinde gösterildiği anlamına gelir.

Bu bağlamda duyarlı bağlam önemlidir. Sinyaller her zaman duyarlı değildir. Tüketicilerini yalnızca temel grafik reaktif bağlamda çalıştığında uyarırlar. Reaktif bağlam, modeldeki bir sinyalin kullanılması veya modeldeki bir sinyale erişimdir. effect().

“Sinyal” terimi belirsiz olduğundan bu noktada kısa bir açıklama yapalım: Yukarıda sunulan kavrama ek olarak sinyaller işlevler sağlar. computed() birlikte signal() veri türü [WritableSignal] sırasıyla [Signal] Geriye doğru. Sinyal terimine uygulanan dört biçim vardır: kavram olarak sinyaller, Angular'da uygulanması olarak sinyaller, Signal veri türü e olarak signal işlev olarak.

Bileşen ağaçlarından grafiklere geçmenin sonucu Angular'ın oluşturmayı bir yan etki olarak görmesidir. Bir sinyal bir bileşene değişiklik bildirdiğinde, bu bileşen bir yan etki olarak görüntülenmeye başlar.




Sinyallerle açısal oluşturma



Sinyallerle açısal oluşturma


(Fotoğraf: Rainer Hahnekamp)



Yeni oluşturma modelini çerçeveye tam olarak dahil etmek için özel bir bileşene, sinyal bileşenine ihtiyaç vardır. Signal Components, Angular 17 için uzun süredir duyuruldu ancak daha sonra sürüm 18 veya 19'a geri çekildi.

Ayrıca plan, mevcut sinyal işlevselliğini sürüm 17 ile birlikte geliştirici önizlemesinden çıkarmaktı. Durum böyle değil veya yalnızca kısmen öyle.

Son dakika değişiklikleri


Sadece iki fonksiyon signal() VE computed() kararlı olarak işaretlenirler. effect() ancak yine de bir geliştirici önizlemesidir. Bunun temel nedeni, içindeki kodun effect() Angular framework'ün işlevlerine erişir. Bu Angular çerçeve işlevleri sırayla sinyallere erişirse, effect() bunları daha fazla kaydederseniz geliştiriciler izini kaybeder.

Orada olsalar bile signal() VE computed() istikrarlı, ama buna engel olamazsın effect() Bu, sinyallerin genel olarak gerçekten “kararlı” olmadığı anlamına gelir.

Bunun arasında bir fark var Signal (çocuk kim signal() sürüm 16 ve 17'de oluşturuldu. Angular 16'da değeri bir aracılığıyla ayarlamak hala mümkündü. mutate()Fonksiyonu değiştirmek için sinyal değişikliğinin artık yalnızca değişmez bir şekilde gerçekleşmesi gerekir.

Örneğin, sürüm 16'da aşağıdaki kod sorunsuz bir şekilde mümkündü:


const city = signal({
name: 'Vienna',
population: 1_982_097
})

city.mutate(value => value.name = 'Wien')


Sürüm 17'den itibaren değişiklik yalnızca aracılığıyla yapılmalıdır. set() VEYA update() yer almak.


const city = signal({
name: 'Vienna',
population: 1_982_097
})

city.update(value => ({...value, name: 'Wien'}))
city.set({name: 'Berlin', population: 3_755_251});


Burada geliştiricilerin sinyalin bildirim göndermesi için yeni bir nesne referansı oluşturması gerekiyor.

Yerel değişiklik tespiti


Angular takımının bunu son dakikada yapmasından hayal kırıklığına uğrayan herkes effect() kendisini geliştirici önizleme durumuna yerleştirdi ve beklenmedik bir sürprizle karşılaştı: aracılığıyla yerel değişiklik tespiti OnPushancak bu yalnızca bir sinyalle birlikte çalışır.

Bir ön uç çerçevesine, oluşturmanın farklı şekillerde gerçekleşmesi gerektiği bildirilebilir. Angular'da, sinyal bileşenleri görünene kadar değişiklik tespiti sorumludur. Mevcut bileşen modeliyle çerçeve, durumun ne zaman ve nerede değiştiğini bilmiyor ve bir DOM güncellemesi gerekiyor.

Bu nedenle Zone.js kütüphanesi arka planda çalışır. Zone.js, sinyal bileşenlerinin piyasaya sürülmesiyle de tarihe geçecek. Kütüphane her DOM olayını ve ayrıca eşzamansız görevlerin ne zaman tamamlandığını bilir. Her iki olay da güncelleme gerektirebilir.

Bu nedenle Zone.js değişiklik takibini etkinleştirir. Bunu yapmak için Angular, bileşen ağacı aracılığıyla her bir bileşene bakar ve bir değişiklik olup olmadığını kontrol eder. Cevabınız evet ise DOM'daki ilgili bölümü güncelleyin.




Standart ayarlarla algılamayı değiştirin



Standart ayarlarla algılamayı değiştirin


(Fotoğraf: Rainer Hahnekamp)



Bu süreç çok verimli değildir. Örneğin, bir olay işleyicisi yalnızca konsola çıktı gönderirse durum değişmez ve değişiklik takibi ücretsiz olarak gerçekleştirilir.

Artık değişiklik izlemeyi ayarlamak için bir eklenti ayarı var OnPush. Dolayısıyla değişiklik tespiti yalnızca bu bileşeni ve onun alt öğelerini “kirli” olarak işaretlenmişse kontrol eder.

Bu işareti çeşitli işlemler ayarlayabilir. Bazı örnekler:

  • Bir olay işleyicisi tarafından işlenen bir DOM olayı meydana gelir.
  • Bir ana bileşen, verileri yeni bir nesne referansıyla alt bileşene iletir.
  • Modelde async-Tüp seti.
  • Bir sinyal modelde yeni bir değeri tetikler.
Ancak “kirli” işareti yalnızca asıl bileşende görülmez, aynı zamanda ana bileşenlere de işaret etmelidir. Aynı zamanda bir ana bileşen olarak da kullanılmalıdır. OnPush uyguladığınızda değişiklik takibi çocuğa ulaşmıyordu.

Bir bileşen, bileşen ağacında çok derindeyse, Angular onu kontrol eder. OnPush – hatta ana bileşenler.




OnPush ve standartla birleştirilmiş değişiklik algılama: OnPush'ta olay



OnPush ve standartla birleştirilmiş değişiklik algılama: OnPush'ta olay


(Fotoğraf: Rainer Hahnekamp)





OnPush ve karma standartla algılamayı değiştirin: Standartta olay



OnPush ve karma standartla algılamayı değiştirin: Standartta olay


(Fotoğraf: Rainer Hahnekamp)



Angular 17.0 artık değişiklik izlemenin ana bileşeni atladığı yerel değişiklik izlemeyi sunuyor.

Yerel değişiklik tespitinin çalışması için durum değişikliğinin öncelikle bir sinyalde gerçekleşmesi gerekir. İkinci olarak, tüm ana bileşenlerin OnPush Sahip olmak.




Sinyal değiştiğinde yerel değişiklik tespiti



Sinyal değiştiğinde yerel değişiklik tespiti


(Fotoğraf: Rainer Hahnekamp)



Aşağıdaki kod minimal bir örnektir:


@Component({
template: `
<div>
<mat-table [dataSource]="dataSource">
<!-- code für HTML –->
</mat-table>
<div class="flex items-center">
@if (lastUpdate) {
<app-timer [lastUpdate]="lastUpdate"></app-timer>
}
<button (click)="refresh()">Refresh</button>
</div>
</div>
`,
standalone: true,
imports: [MatTableModule, TimerComponent],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent implements OnInit {
lastUpdate: Date | undefined
dataSource = new MatTableDataSource<Holiday[]>([]);
displayedColumns = ['title', 'description'];

ngOnInit() {
this.refresh()
}

refresh() {
fetch('https://api.eternal-holidays.net/holiday').then(res => res.json()).then(value => {
this.lastUpdate = new Date();
this.dataSource.data = value;
});
}
}


@Component({
selector: 'app-timer',
template: `<span>Last Updated: {{ lastUpdateInSeconds() }}</span>`,
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [DatePipe, DecimalPipe, AsyncPipe]
})
export class TimerComponent {
@Input() lastUpdate = new Date();
lastUpdateInSeconds = signal(0)

constructor() {
setInterval(() => {
this.lastUpdateInSeconds.set((new Date().getTime() - this.lastUpdate.getTime()) / 1_000);
}, 1000);
}
}


Bileşen listede TimerComponent bir oğlu ListComponent. TimerComponent son güncellemeden bu yana geçen saniyeyi gösterir. Bunu yapmak için bileşen değerini günceller. lastUpdateInSeconds her saniye.

Her iki bileşenin de özelliği olmasına rağmen OnPush Angular 16'daki değişiklik tespiti bile her zaman aynı olacaktır ListComponent kontrol etmek. Angular 17'den başlayarak kontrol yalnızca dosyada gerçekleşir TimerComponent yerine. Ama bunun nedeni sadece lastUpdateInSeconds() bu bir sinyal. Eğer sınıfın normal bir özelliği olsaydı yerel değişiklik tespiti işe yaramazdı.



Haberin Sonu
 
Üst