REACT RENDERING MEKANİZMASINI ANLAMAK

Vimaj8 dk okuma
React mavi atom logosu yanında 3 ardışık virtual DOM ağaç snapshot diff farklı node'lar vurgulu render mekanizması temsili

"React niye yavaş?" sorusunun cevabı çoğunlukla aynı: gereksiz render. Bir parent component her state değişikliğinde tüm child'larını yeniden render ediyor; sayfa donuyor. React rendering mekanizmasını anlamak performans optimizasyonunun anahtarı.

1. Render nedir?

React'ta render bir component'in fonksiyonunun çalıştırılmasıdır. Sonuç: JSX (aslında JavaScript objesi) döner. Bu obje virtual DOM'a yazılır; React virtual DOM'u önceki haliyle karşılaştırır ve sadece farkı gerçek DOM'a uygular — bu reconciliation modelinin resmi açıklaması React öğrenme dokümantasyonunda ele alınır.

Render iki fazda gerçekleşir

  1. Render phase: Component fonksiyonu çalışır; virtual DOM oluşur. Saf, side-effect'siz.
  2. Commit phase: Virtual DOM'daki değişiklikler gerçek DOM'a yazılır. useEffect çalışır.

2. Render'ı tetikleyen durumlar

  • İlk mount: Component ilk kez ekrana geldiğinde
  • State değişikliği: useState, useReducer çağrıldığında
  • Props değişikliği: Parent re-render olunca
  • Context değişikliği: useContext'in dinlediği context güncellenince
  • Parent re-render: Üst component yeniden render olunca (props değişmemiş bile olsa)

3. Gereksiz render problemi

function Parent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
      <ExpensiveChild />
    </div>
  );
}

ExpensiveChild count'a bağlı olmasa bile her tıklamada yeniden render olur. Parent re-render olduğu için tüm child'lar default olarak yeniden render olur.

4. React.memo: bileşen memoization

const ExpensiveChild = React.memo(function ExpensiveChild() {
  return <div>Pahalı içerik</div>;
});

React.memo shallow comparison ile props'ları karşılaştırır; aynıysa render etmez. Reference equality kontrolü; objeler/fonksiyonlar için her render'da yeni reference oluştuğu için işe yaramayabilir.

5. useMemo: değer memoization

function ProductList({ products, filter }) {
  const filtered = useMemo(() => {
    return products.filter(p => p.category === filter);
  }, [products, filter]);

  return (
    <ul>
      {filtered.map(p => <li key={p.id}>{p.name}</li>)}
    </ul>
  );
}

1000 elemanlı array'i her render'da filter etmek yerine; sadece products veya filter değiştiğinde filtrelenir.

6. useCallback: fonksiyon memoization

function Parent() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    console.log('Clicked');
  }, []);

  return <Child onClick={handleClick} />;
}

const Child = React.memo(function Child({ onClick }) {
  return <button onClick={onClick}>Click</button>;
});

useCallback olmazsa handleClick her render'da yeni referans alır; React.memo'ya rağmen Child yeniden render olur.

7. Virtual DOM ve reconciliation

React render edilen JSX'i virtual DOM'a yazar; önceki virtual DOM ile karşılaştırır. Bu sürece "reconciliation" denir.

Key prop'unun önemi

// Yanlış: array index key
{products.map((p, i) => (
  <Product key={i} data={p} />
))}

// Doğru: unique ID
{products.map(p => (
  <Product key={p.id} data={p} />
))}

Liste değişikliklerinde (eleman eklemek, silmek, sıralamak) React key ile hangi elemanın değiştiğini anlar. Index key kullanmak yanlış davranışlara yol açar; özellikle sıralı listelerde.

VS Code dark theme React fonksiyonel bileşen kodu useState ve JSX dönüşü ile render phase ve commit phase yorum satırları

8. React DevTools Profiler

Performance sorunlarını tespit etmek için en güçlü araç:

  1. React DevTools yüklü olmalı (Chrome eklentisi)
  2. Profiler sekmesine geç
  3. "Start profiling" tuşuna bas
  4. Sayfayı kullan
  5. "Stop profiling"
  6. Hangi component'in ne kadar süre render olduğunu gör

Renkli flame graph; en uzun süren component'ler kırmızı. Burası optimizasyon başlangıç noktası.

9. Render optimizasyon stratejileri

1. State'i yukarı çıkarmaktan kaçın

State component ağacının ne kadar üstündeyse o kadar çok child'ı etkiler. State'i kullanıldığı yerin en yakınında tut.

2. Component splitting

Büyük component'leri parçala. Yalnızca değişen parça re-render olur.

3. React.memo doğru yerlerde

Her component'i memo ile sarma; sadece pahalı render eden veya çok kez render edilen component'lerde.

4. children prop pattern

function App() {
  return (
    <Counter>
      <SlowComponent />
    </Counter>
  );
}

function Counter({ children }) {
  const [count, setCount] = useState(0);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>{count}</button>
      {children}
    </div>
  );
}

children prop her render'da aynı reference olduğu için SlowComponent re-render olmaz.

5. Context split

Tek bir context'te çok veri varsa, küçük context'lere böl. Her context değişiminde sadece o context'i tüketenler re-render olur.

10. React 19 ve concurrent features

useTransition

Yavaş state update'leri "transition" olarak işaretle; kullanıcı arayüzü bloklanmaz.

const [isPending, startTransition] = useTransition();

function handleSearch(query) {
  startTransition(() => {
    setResults(filterLargeList(query));
  });
}

useDeferredValue

Bir değerin güncellemesini ertele; kullanıcı yazarken kasmasın.

const deferredQuery = useDeferredValue(query);

11. Yaygın performans hataları

  1. Inline object/array prop'u. <Comp style={{color: 'red'}} /> her render yeni obje
  2. Inline function. onClick={() => doSomething()} her render yeni fonksiyon
  3. useState ile array index key. Yanlış reconciliation
  4. useEffect dependency eksik. Sonsuz render döngüsü
  5. Context'i çok büyük tutmak. Tek değişiklik tüm consumer'ları etkiler
  6. Map'ten önce filter chain'i. Her render'da yeni hesaplama; useMemo gerek
Chrome React DevTools Profiler paneli flame graph component render süreleri renkli barlar Ranked sıralama paneli ve commits zaman çizgisi

12. Konu Üzerinde Derinleşmek

React rendering ve performance optimizasyonu modern frontend için temel beceriler. Konuyu profesyonel düzeyde işlemek için uygulamalı React eğitimi programları rendering ve hook konularını derinlemesine işler.

13. Adımların Özeti

React rendering; state veya props değişikliğinde component'in yeniden çalışması, virtual DOM ile karşılaştırılması ve sadece farkın gerçek DOM'a uygulanması. Gereksiz re-render performans yer; React.memo, useMemo, useCallback ile önlenir. State'i kullanıldığı yerin yakınında tutmak, key prop'u doğru kullanmak, children pattern'i ve context split temel optimizasyon stratejileri. React DevTools Profiler ile darboğazlar tespit edilir.

Sıkça Sorulan Sorular

Her component'i React.memo ile sarmam gerek mi?

Hayır, çoğunlukla gereksiz. React.memo memoization yapar; props karşılaştırması maliyeti var. Hafif component'lerde bu maliyet render'ın kendisinden fazla olabilir. Memo sadece: 1) Pahalı render eden component'ler, 2) Sık re-render olan component'ler, 3) Props nadiren değişen component'ler için kullanılmalı. Her yerde memo kullanmak premature optimization.

useMemo ne zaman gerçekten gerekli?

Pahalı hesaplamalarda. 1000+ eleman filter/sort/reduce işlemleri için useMemo değerli. Basit hesaplamalar (a + b, string concat) için useMemo overhead'i hesaplamanın kendisinden fazla. Genel kural: hesaplama 1ms'den uzunsa veya re-render çok sıksa useMemo düşünülür.

useCallback ne zaman gerekli?

Sadece iki durumda. Birincisi: fonksiyon bir memo'lu child'a prop olarak geçiriliyorsa. İkincisi: fonksiyon useEffect veya useMemo dependency'siyse. Diğer durumlarda useCallback overhead'dir; fonksiyonu wrap etmek değer üretmez. 'Her yere useCallback' antipattern; performance'ı düşürebilir.

Key prop neden bu kadar önemli?

React reconciliation key prop'u kullanarak hangi liste elemanının değiştiğini anlar. Index key ile sıralı listede eleman ekleyince/silince React her elementi 'değişti' sanır; tüm listeyi yeniden render eder. Unique ID key ile sadece gerçekten değişen element re-render olur. Performans + doğru davranış için unique ID şart.

useTransition ne zaman kullanılır?

Yavaş state update'leri için. Örnek: 10.000 elemanlı listede arama; her tuş basışında filter çalışır, UI donar. useTransition ile arama transition olarak işaretlenir; React önce input'u günceller (hızlı), sonra arka planda filtreleme yapar. Kullanıcı yazarken kasma hissi azalır. React 18+ özelliği.

Profiler'da hangi sayıya bakmalıyım?

Üç ana metrik: Render duration (component render süresi), Commit duration (DOM update süresi), ve render count (kaç kez render). 50ms üstü uzun task; UX'i bozar. Aynı component'in çok kez render etmesi (count) gereksiz render sinyali. Flame graph'ta kırmızı bar'lar dikkat istenir.

Context API yerine ne kullanmalı?

Bağlamına göre. Çok sık değişen state için Context yavaş; Zustand, Jotai veya Recoil tercih edilir. Az değişen global state (theme, locale, user) için Context yeterli. Server state için React Query. Context overkill'i en sık antipattern; basit prop drilling kabul edilebilir, context her zaman doğru çözüm değil.

 Vimaj