TypeScript - Angular markForCheck vs detectChanges
Bu soruya, StackOverflow'da benzer bir soru gördüğüm düşüncesiyle başlayacağım, ama o soruda sadece fark için bir cevap vardı.
Sorduğum şey, duruma bağlı olarak ne kullanmam gerektiği ve bir yöntemin diğerine göre hangi dezavantajlara sahip olabileceği.
detectChanges öğe ve onun alt öğeleri üzerinde anında değişiklik tespit döngüsünü çalıştırırken, markForCheck yalnızca mevcut öğeyi ve onun atalarını kirli olarak işaretler ve bir sonraki değişiklik tespit döngüsünde kontrol edilmeleri gerektiğini belirtir.
Bunu çoğunlukla, asenkron çağrılarda her zaman markForCheck kullanmam gerektiğini hissetmediğim için soruyorum.
Örneğin, normal bir HTML girişi için bir sarmalayıcı olan bir InputComponent'im var. Bu InputComponent'te ChangeDetectionStrategy.OnPush etkinleştirilmiş durumda.
Sunucuya asenkron bir çağrı yaptığımda ve ihtiyacım olan veriyi aldığımda, bir seçenekler listesi güncellemek için o InputComponent'te değişiklik tespitini çalıştırmam gerekiyor ve bunun için iki seçeneğim var.
İlk olarak (kullanıyor olmam gerektiğini hissettiğim) detectChanges çünkü bu sadece tam olarak bu bileşen için kontrolleri uygular, oysa markForCheck tüm ağaç dalının kontrol edilmesine neden olur.
Peki ne kullanmalıyım ve markForCheck'i hiç kullanmam gerekiyor mu ve neden?
Cevap #1
Sorduğum şey, duruma bağlı olarak ne kullanmam gerektiği ve bir yöntemin diğerine göre hangi dezavantajlara sahip olabileceğidir.
Asla detectChanges() çağırmamalısınız.
Geliştiriciye değer katacak iyi bir uç durum detectChanges() yoktur. Genellikle, değişmezlik, durum yönetimi ve bileşen değişikliklerinin programcı tarafından iyi yönetilmediği projelerde kullanılır.
detectChanges() gerektiren tüm kaynak kod, bunun gerekli olmadığı şekilde yeniden yazılabilir.
Öte yandan, markForCheck() kullanılması gereken iyi özel durumlara sahiptir.
Bunu özellikle soruyorum çünkü async çağrılarda her zaman markForCheck kullanmam gerektiğini düşünmüyorum.
Genellikle markForCheck() çağıran kaynak kodunun yakınında this referansına rastlarsınız.
@Component({...})
export class ExampleComponent {
//......
public function work() {
this.httpClient.get(...).subscribe(resp =>
this.data = resp.data;
this.changeDetectorRef.markForCheck();
});
}
}
Fonksiyonel programlamada, this referansı kirlidir ve fonksiyonun kapsamı dışında bir dış durumu değiştirir. Fonksiyonel programlamanın en iyi uygulamalarından sapmak, her şeyin çalışır durumda kalmasını sağlamak için düzeltmeler gerektiren sorunları ortaya çıkarır. Asenkron işlemlerinizle yalnızca saf fonksiyonlar yazarsanız, asla markForCheck() çağırmak zorunda kalmazsınız, ancak bir this referansı eklediğinizde, bileşenin durumu değiştirilir ve görünümün bilgilendirilmesi gerekir.
Yukarıda yanlış bir şey yok, ancak aynı zamanda RxJS aboneliklerinde this kullanımının aşırı olması, bakımı zor olabilecek kaynak kodu oluşturur.
Kaynak kodunuzu reaktif programlamayı kullanacak şekilde yeniden yazmanız ve şablonda async borusunu kullanmanız daha iyidir. Anahtar nokta, bileşen üzerinde özelliklerin güncellenmesine gerek kalmayacak şekilde durumsuz bileşenler yaratmaktır. Her şey reaktif bir akış olarak yapılır.
@Component({
template: `<ng-container *ngIf="data$ | async as data">
<!-- stuff -->
</ng-container>`,
// .....
})
export class ExampleComponent {
public data$: Observable<any>;
public function work() {
this.data$ = this.httpClient.get(...).pipe(shareReplay(1));
}
}
Bileşenlerinizi durumsuz olacak şekilde tasarlarsanız ve veri işlemenin tümü için RxJS kullanırsanız, markForCheck() kullanma zorunluluğu olmamalıdır. DOM olaylarını dinleseniz bile, veriler this kullanmaktan kaçınmak için diğer observable'lara yönlendirilebilir.
Bazen markForCheck() çağırmanız gereken zamanlar olacaktır. Ancak, bunu kullanmaktan kaçınmak için yaklaşımınızı durup yeniden düşünmenizi öneririm, çünkü onu gerektirmeyen başka bir yol olmalıdır.
Cevap #2
Bu sorunun sorulduğu zamandan bu yana birçok yıl geçti. Ve bazı şeyler değişti.
Şu anda bu soruyla ilgilenen insanların çoğu signal kullanarak daha iyi durumda.
Onlar basittir. Etkilidirler. Güncelleme sırasında değişiklik tespitini tetiklerler (Angular v18'den itibaren) değer değişikliğine neden olan bir olay Angular bölgesi dışında oluşsa bile. Ayrıca, Angular v18'den itibaren deneysel bölgessiz değişiklik tespitini etkinleştirebilir ve bu gayet iyi çalışır.
Ayrıca, bir sinyalin değeri güncellendiğinde - yalnızca o sinyali kullanan bileşenler değişiklikler için kontrol edilecektir (uygulamanız tüm bileşenlerde OnPush kullanıyorsa, çünkü hala eski değişiklik algılama tarafından çalıştırılmaktadır).
Bu, sinyallerin kullanımını markForCheck ve detectChanges'e kıyasla bir gümüş kurşun gibi yapar.
Gelecekte, sinyal bileşenleri alacağız ve bunlar daha da performanslı olacak, ancak şablonlarda render edilmesi gereken ve güncellenen durum tutucu özellikler için sinyalleri kullandıysanız kodunuzu değiştirmeniz gerekmeyecek (değişmeyen bir statik değeri render ediyorsanız - sinyalleri atlayabilirsiniz çünkü zaten render edilecektir).
“detectChanges öğesini asla kullanmayın” konusuyla ilgili olarak, bu ifadeye sadece kısmen katılıyorum. Eğer bunun gerekli olduğundan %100 emin iseniz ve Angular'da değişiklik tespitinin nasıl çalıştığını biliyorsanız, bunu kullanabilirsiniz. Bu tamamen uygundur.
Ama çoğu insan ve çoğu kullanım durumu için markForCheck, asla zarar veremeyecek ve %99,99999 senaryoda mükemmel çalışacak bir "başvurulacak" çözümdür.
