Angular, son bir yılda geliştiricilerin Core Web Vitals puanlarını iyileştirmesine ve son kullanıcılarına mükemmel bir deneyim sunmasına yardımcı olmak için rehydrate ve ertelenebilir görünümler gibi birçok yeni özellik kazandı. Akış ve kısmi besleme gibi bu işlevi temel alan sunucu tarafı oluşturma ile ilgili ek özellikler üzerinde de araştırmalar devam etmektedir.
Maalesef uygulamanızın veya kitaplığınızın tüm bu yeni ve gelecekteki özelliklerden tam olarak yararlanmasını engelleyebilecek bir kalıp vardır: Temel DOM yapısının manuel olarak değiştirilmesi. Angular, bir bileşenin sunucu tarafından serileştirildiği andan tarayıcıda beslenene kadar DOM yapısının tutarlı kalmasını gerektirir. DOM'u beslemeden önce DOM'a manuel olarak eklemek, taşımak veya DOM'dan kaldırmak için ElementRef
, Renderer2
veya DOM API'lerini kullanmak, bu özelliklerin çalışmasını engelleyen tutarsızlıklara neden olabilir.
Ancak, manuel DOM değiştirme ve erişimin tamamı sorunlu değildir ve bazen gereklidir. DOM'u güvenli bir şekilde kullanmanın anahtarı, DOM'a olan ihtiyacınızı mümkün olduğunca en aza indirmek ve ardından DOM'u mümkün olduğunca uzun süre ertelemek olacaktır. Aşağıdaki yönergelerde, bunu nasıl başarabileceğiniz ve Angular'ın yeni ve gelecekteki tüm özelliklerinden tam olarak yararlanabilecek, gerçekten evrensel ve geleceğe hazır Angular bileşenleri oluşturabileceğiniz açıklanmaktadır.
Manuel DOM manipülasyonundan kaçının
Manuel DOM değiştirmenin neden olduğu sorunları önlemenin en iyi yolu, şaşırtıcı olmayan bir şekilde, mümkün olduğunda bu işlemi tamamen yapmaktan kaçınmaktır. Angular, DOM'un çoğu yönünü değiştirebilen yerleşik API'lere ve kalıplara sahiptir: DOM'a doğrudan erişmek yerine bunları kullanmayı tercih etmeniz gerekir.
Bir bileşenin kendi DOM öğesini değiştirme
Bir bileşen veya yönerge yazarken, barındırıcı öğeyi (yani bileşenin veya yönergenin seçicisiyle eşleşen DOM öğesini) değiştirmeniz gerekebilir. Örneğin, bir sarmalayıcı öğeyi hedeflemek veya tanıtmak yerine sınıf, stil veya özellik eklemek için barındırıcı öğeyi değiştirmeniz gerekebilir. Temel DOM öğesini değiştirmek için ElementRef
öğesine başvurmak cazip gelebilir. Bunun yerine, değerleri bir ifadeye açık bir şekilde bağlamak için ana makine bağlamalarını kullanmanız gerekir:
@Component({
selector: 'my-component',
template: `...`,
host: {
'[class.foo]': 'true'
},
})
export class MyComponent {
/* ... */
}
HTML'de veri bağlama ile aynı şekilde, örneğin özelliklere ve stillere de bağlama yapabilirsiniz. Ayrıca 'true'
değerini, Angular'ın gerektiğinde değeri otomatik olarak eklemek veya kaldırmak için kullanacağı farklı bir ifadeyle değiştirebilirsiniz.
Bazı durumlarda anahtarın dinamik olarak hesaplanması gerekir. Ayrıca, bir değer kümesi veya haritası döndüren bir sinyale ya da işleve de bağlanabilirsiniz:
@Component({
selector: 'my-component',
template: `...`,
host: {
'[class.foo]': 'true',
'[class]': 'classes()'
},
})
export class MyComponent {
size = signal('large');
classes = computed(() => {
return [`size-${this.size()}`];
});
}
Daha karmaşık uygulamalarda, ExpressionChangedAfterItHasBeenCheckedError
'den kaçınmak için manuel DOM manipülasyonuna başvurmak cazip gelebilir. Bunun yerine, önceki örnekte olduğu gibi değeri bir sinyale bağlayabilirsiniz. Bu işlem gerektiğinde yapılabilir ve kod tabanınızın tamamında sinyallerin benimsenmesini gerektirmez.
Bir şablonun dışındaki DOM öğelerini değiştirme
Normalde erişilemeyen öğelere (ör. başka bir ana veya alt bileşene ait öğeler) erişmek için DOM'u kullanmayı denemek cazip gelebilir. Ancak bu yöntem hataya açıktır, kapsüllemeyi ihlal eder ve bu bileşenlerin gelecekte değiştirilmesini veya yükseltilmesini zorlaştırır.
Bunun yerine, bileşeniniz diğer tüm bileşenleri kara kutu olarak kabul etmelidir. Diğer bileşenlerin (aynı uygulama veya kitaplıktaki bileşenler dahil) ne zaman ve nerede bileşeninizin davranışıyla ya da görünümüyle etkileşim kurması veya bunları özelleştirmesi gerekebileceğini düşünün ve ardından bunu yapmanın güvenli ve belgelenmiş bir yolunu sunun. Basit @Input
ve @Output
mülkleri yeterli olmadığında bir API'yi alt ağaç için kullanılabilir hale getirmek üzere hiyerarşik bağımlılık ekleme gibi özellikleri kullanın.
Geçmişte, modal iletişim kutuları veya ipuçları gibi özellikleri uygulamak için <body>
öğesinin sonuna veya başka bir ana öğeye bir öğe ekleyip içeriği buraya taşımak veya yansıtmak yaygın bir uygulamaydı. Ancak günümüzde şablonunuzda bunun yerine basit bir <dialog>
öğesi oluşturabilirsiniz:
@Component({
selector: 'my-component',
template: `<dialog #dialog>Hello World</dialog>`,
})
export class MyComponent {
@ViewChild('dialog') dialogRef!: ElementRef;
constructor() {
afterNextRender(() => {
this.dialogRef.nativeElement.showModal();
});
}
}
Manuel DOM değiştirme işlemini erteleme
Doğrudan DOM değiştirme işleminizi en aza indirmek ve mümkün olduğunca fazla erişmek için önceki kuralları kullandıktan sonra, kaçınılmaz olarak bazı işlemler kalabilir. Bu gibi durumlarda, mümkün olduğunca ertelemek önemlidir. afterRender
ve afterNextRender
geri çağırma işlevleri, Angular değişiklikleri kontrol edip DOM'a kaydettikten sonra yalnızca tarayıcıda çalıştıkları için bunu yapmanın mükemmel bir yoludur.
Yalnızca tarayıcıda JavaScript çalıştırma
Bazı durumlarda yalnızca tarayıcıda çalışan bir kitaplığınız veya API'niz olur (ör. grafik kitaplığı, bazı IntersectionObserver
kullanımları vb.). Tarayıcıda çalıştırıp çalıştırmadığınızı koşullu olarak kontrol etmek veya sunucudaki davranışı kesmek yerine afterNextRender
kullanabilirsiniz:
@Component({
/* ... */
})
export class MyComponent {
@ViewChild('chart') chartRef: ElementRef;
myChart: MyChart|null = null;
constructor() {
afterNextRender(() => {
this.myChart = new MyChart(this.chartRef.nativeElement);
});
}
}
Özel düzen gerçekleştirme
Bazen, hedef tarayıcılarınızın henüz desteklemediği bazı düzenleri (ör. ipucu konumlandırma) gerçekleştirmek için DOM'u okumanız veya DOM'a yazmanız gerekebilir. DOM'un tutarlı bir durumda olduğundan emin olabileceğiniz için afterRender
bu işlem için mükemmel bir seçimdir. afterRender
ve afterNextRender
, EarlyRead
, Read
veya Write
değerine sahip bir phase
değerini kabul eder. DOM düzenini yazıldıktan sonra okumak, tarayıcıyı düzeni senkronize olarak yeniden hesaplamaya zorlar. Bu da performansı ciddi şekilde etkileyebilir (düzen karmaşası bölümüne bakın). Bu nedenle mantığınızı doğru aşamalara dikkatlice ayırmanız önemlidir.
Örneğin, sayfadaki başka bir öğeye göre ipucu görüntülemek isteyen bir ipucu bileşeni büyük olasılıkla iki aşama kullanır. EarlyRead
aşaması, öncelikle öğelerin boyutunu ve konumunu elde etmek için kullanılır:
afterRender(() => {
targetRect = targetEl.getBoundingClientRect();
tooltipRect = tooltipEl.getBoundingClientRect();
}, { phase: AfterRenderPhase.EarlyRead },
);
Ardından Write
aşaması, ipucu metnini yeniden konumlandırmak için önceden okunan değeri kullanır:
afterRender(() => {
tooltipEl.style.setProperty('left', `${targetRect.left + targetRect.width / 2 - tooltipRect.width / 2}px`);
tooltipEl.style.setProperty('top', `${targetRect.bottom - 4}px`);
}, { phase: AfterRenderPhase.Write },
);
Mantığımızı doğru aşamalara ayırarak Angular, uygulamadaki diğer tüm bileşenlerde DOM'u etkili bir şekilde toplu olarak değiştirebilir ve performans üzerinde minimum düzeyde etki sağlar.
Sonuç
Kullanıcılarınıza mükemmel bir deneyim sunmanızı kolaylaştırmak amacıyla Angular sunucu tarafı oluşturma konusunda yakın gelecekte birçok yeni ve heyecan verici iyileştirme yapılacak. Önceki ipuçlarının, uygulamalarınızda ve kitaplıklarınızda bu özelliklerden tam olarak yararlanmanıza yardımcı olacağını umuyoruz.