• 16.08.2026 04:31:57
  • Admin Admin

Frontend framework karşılaştırması yaparken API biçiminden çok state değişiminin render maliyetini ölçmek gerekir. React, Angular ve Vue için profil alma, cache sınırı ve migration tekniklerini inceliyoruz.

Frontend Framework Karşılaştırması: State Yönetimi ve Render Maliyeti

Frontend framework karşılaştırması için ölçülebilir state modeli

Bir frontend framework karşılaştırmasında aynı ekranı üç kez yazıp bundle boyutuna bakmak yetersizdir; asıl fark, kullanıcı bir filtre seçtiğinde kaç component'in yeniden hesaplandığı ve kaç DOM düğümünün değiştiğidir. Örneğin ürün listesi için server state'i (API sonucu), URL state'ini (`?q=&page=`) ve geçici UI state'ini (açık popover) tek bir global store'a koymayın. Server state'i TanStack Query, URL state'ini `URLSearchParams`, bileşen yerel state'ini framework'ün kendi primitive'i ile tutarak invalidation alanını sınırlandırın. Bu ayrım, `POST /products/:id` sonrasında yalnızca `['product', id]` sorgusunu geçersiz kılmanızı sağlar; tüm listeyi körlemesine refetch etmez.

Bir web programlama eğitimi veya frontend development eğitimi içinde değerlendirilebilecek somut laboratuvar: 10.000 satırlık tabloya arama filtresi ekleyin, CPU'yu Chrome DevTools Performance panelinden 4× slowdown'a alın ve her tuş vuruşunda `Event: input` ile bir sonraki paint arasındaki süreyi kaydedin. Kabul eşiğini örneğin p75 için 100 ms altında tutun; sadece ortalamayı kullanmak, arka plandaki GC duraklamalarının kullanıcıya yansıyan kuyruk etkisini gizler. Playwright ile CI'da ölçmek için `page.evaluate(() => performance.mark('filter-start'))` ve ekran güncellendikten sonra `requestAnimationFrame` ile `filter-end` işareti bırakılabilir.

ReactJS eğitimi: server state cache ve selector tabanlı render sınırı

reactjs eğitimi projelerinde sık görülen hata, API sonucunu `useEffect` ile bir store'a kopyalayıp ikinci bir doğruluk kaynağı üretmektir. TanStack Query'nin query cache'i varken kopya listeyi Redux/Zustand'a taşımak, optimistic update ile refetch çakıştığında eski cevabın yeni mutation sonucunu ezmesine yol açar. Aşağıdaki örnek, mutation tamamlanınca tüm `products` cache'ini değil yalnızca ilgili kaydı günceller ve liste sorgusunu hedefli biçimde invalidate eder.

import { useMutation, useQueryClient } from '@tanstack/react-query';

type Product = { id: string; stock: number };

export function useReserveProduct() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (id: string) =>
      fetch(`/api/products/${id}/reserve`, { method: 'POST' })
        .then(r => {
          if (!r.ok) throw new Error(`reserve failed: ${r.status}`);
          return r.json() as Promise<Product>;
        }),
    onSuccess: (updated) => {
      queryClient.setQueryData<Product>(['product', updated.id], updated);
      queryClient.invalidateQueries({ queryKey: ['products'] });
    }
  });
}

Render sınırını doğrulamak için React DevTools Profiler'da arama alanına 20 karakter yazın; flamegraph'ta `ProductRow` bileşenlerinin her tuşta commit alıp almadığını kontrol edin. `memo` eklemeden önce prop referanslarını inceleyin: satıra `product` nesnesinin tamamını ve inline `onClick={() => reserve(id)}` göndermek, parent her render olduğunda karşılaştırmayı geçersiz kılar. Büyük listede `@tanstack/react-virtual` ile yalnız görünür satırları üretin; ancak ölçümde önce 10.000 satırın gerçekten DOM'a basıldığını, sonra virtualizer sonrasında DOM düğüm sayısının yaklaşık viewport satırı kadar kaldığını Chrome Elements panelinden doğrulayın.

Angular eğitimi ve VueJS eğitimi: sinyal grafiğini doğru kurmak

angular eğitimi açısından kritik ayrıntı, `computed` içine zamanla değişen fakat reaktif olmayan bir değer koymamaktır. Angular signal yalnızca okuduğu signal bağımlılıklarını izler; `Date.now()` gibi bir çağrı `computed`i kendiliğinden yeniden çalıştırmaz. Aşağıdaki örnekte filtrelenmiş liste yalnızca `query` veya `products` değiştiğinde hesaplanır; template'te her change-detection turunda `products().filter(...)` çağıran bir metot bulunmaz.

import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';

type Product = { id: string; name: string; active: boolean };

@Component({
  selector: 'product-list',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <input (input)="query.set($any($event.target).value)" />
    @for (p of visibleProducts(); track p.id) {
      <product-row [product]="p" />
    }
  `
})
export class ProductListComponent {
  readonly query = signal('');
  readonly products = signal<Product[]>([]);
  readonly visibleProducts = computed(() => {
    const q = this.query().trim().toLocaleLowerCase('tr-TR');
    return this.products().filter(p => p.active && p.name.toLocaleLowerCase('tr-TR').includes(q));
  });
}

vuejs eğitimi tarafında karşılığı, büyük ve değişmeyen API listelerini `reactive()` ile derin proxy'lemek yerine `shallowRef()` içinde saklamaktır. `shallowRef` yalnızca `.value` atamasını izler; satır içindeki alanları mutasyona uğratırsanız UI güncellenmez. Bu nedenle `products.value = products.value.map(...)` gibi immutable güncelleme zorunluluğunu kod inceleme kuralına dönüştürün. Vue Devtools component update vurgusuyla filtre yazarken kaç `ProductRow` güncellendiğini gözlemleyin; Angular'da ise Angular DevTools Profiler ile `OnPush` child'ların gereksiz check almadığını kontrol edin.

JavaScript eğitimi: render öncesi veri dönüştürme ve referans eşitliği

İleri seviye bir javascript eğitimi örneği olarak, aşağıdaki iki yaklaşımın maliyeti aynı değildir: her render'da `sort()` çağırmak hem O(n log n) maliyet üretir hem de `sort` diziyi yerinde değiştirdiği için cache'teki veriyi mutasyona uğratabilir. Kopya üzerinde sıralayın ve cache anahtarına locale ile sıralama yönünü dahil edin. `Intl.Collator` nesnesini her comparator çağrısında oluşturmak yerine bir kez kurmak da 5.000+ satırlı listelerde profilde görünen allocation baskısını azaltır.

const collator = new Intl.Collator('tr-TR', {
  sensitivity: 'base',
  numeric: true
});

export function sortedProducts(products: readonly Product[]) {
  return [...products].sort((a, b) => collator.compare(a.name, b.name));
}

// Hatalı: products.sort(...) cache veya store içindeki diziyi değiştirir.
// Doğru: yeni referans döndüğü için selector/memo katmanı değişimi izleyebilir.

Önce-sonra doğrulamasını yalnız FPS ile yapmayın. Chrome Performance kaydında önce `Function Call` altında comparator çağrı sayısını, ardından Memory panelinde allocation timeline'ını karşılaştırın. Örnek hedef: filtreleme sırasında her input event'inde 5.000 `Intl.Collator` nesnesi yerine sıfır yeni collator oluşturmak. Ayrıca Türkçe karakterlerde `toLowerCase()` ile `toLocaleLowerCase('tr-TR')` aynı sonucu vermez; `I/İ` içeren ürün aramasında yanlış eşleşme, performans testi geçse bile işlevsel regresyondur.

AngularJS eğitimi ve React Native eğitimi için paylaşılan domain sınırı

angularjs eğitimi bağlamında legacy uygulamayı React, Angular veya Vue'ya geçirirken ilk hedef `ng-repeat`i tek seferde çevirmek olmamalıdır. API istemcisi, doğrulama ve domain tiplerini framework bağımsız bir TypeScript paketine taşıyın; `@angularjs/upgrade` yalnızca geçiş köprüsüdür, kalıcı state katmanı değildir. Monorepo'da `packages/catalog-domain` paketini `tsc --noEmit` ile bağımsız derleyin ve UI paketlerinin bu paketten yalnız tip/iş kuralı import etmesini ESLint `no-restricted-imports` kuralıyla zorlayın.

react native eğitimi alan ekipler de aynı domain paketini kullanabilir; fakat `window`, `localStorage` ve DOM event tiplerini shared pakete sızdırmayın. Tarayıcı token deposunu web adapter'ında, mobil secure storage'ı React Native adapter'ında bırakın. Örneğin domain katmanı `reserveProduct(http, id)` şeklinde `HttpClient` arayüzü alırsa web'de `fetch`, mobilde platform istemcisi enjekte edilir. Bu tasarımın testi için Vitest ile sahte istemci kullanın: `expect(fake.calls[0].url).toBe('/products/p1/reserve')`; UI framework'ünü mount etmeden idempotency header ve hata eşleme kurallarını doğrularsınız.

Sık Sorulan Sorular

ReactJS eğitimi sırasında gereksiz render nasıl ölçülür?

React DevTools Profiler'da gerçek bir filtreleme senaryosunu kaydedin, commit sayısını ve her commit'in süresini karşılaştırın. Ardından `ProductRow` için prop referanslarını stabil hale getirip aynı senaryoyu tekrar çalıştırın; yalnız `memo` eklemek yerine hangi parent state değişiminin satırlara yayıldığını flamegraph'tan bulun.

Angular eğitimi için signals mi RxJS mi kullanılmalı?

HTTP sonucu, debounce, retry ve iptal gerektiren akışlar için RxJS kullanın; template'e sunulan türetilmiş yerel değer için observable sonucunu signal'a köprüleyip `computed` kullanın. `switchMap` arama isteğinde önceki isteği iptal eder; `mergeMap` aynı senaryoda eski cevabın yeni arama sonucunu ezmesine neden olabilir.

VueJS eğitimi projelerinde shallowRef ne zaman kullanılmalı?

Büyük API listesi çoğunlukla bütün dizi olarak değişiyorsa `shallowRef([])` kullanın ve güncellemeyi yeni dizi atayarak yapın. Satır alanını doğrudan `products.value[0].name = 'x'` ile değiştirirseniz shallow reactivity tetiklenmez; immutable `map` güncellemesi veya bilinçli `triggerRef` gerekir.

Frontend framework karşılaştırması için hangi performans metrikleri alınmalı?

Aynı veri seti ve aynı CPU throttle altında input-to-next-paint süresi, DOM düğüm sayısı, commit/check sayısı ve JS heap allocation ölçün. Chrome Performance, React DevTools Profiler, Angular DevTools ve Vue Devtools sonuçlarını ayrı ayrı kaydedin; bundle boyutu bu dört kullanıcı-etkileşimi metriğinin yerine geçmez.

AI / LLM Discovery

Bu makale Opendart Akademi Web Programlama eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt