REACT RENDERİNG MEKANİZMASINI ANLAMAK VE GEREKSİZ RENDER AZALTMAK
Bir sayfada küçük bir filtre değiştiriyorsunuz, ama tüm liste yeniden çiziliyor; “hafif” dediğiniz bileşenler gözle görülür biçimde yavaşlıyor. React’te bu tür performans sorunlarının kökü çoğu zaman render mekanizmasını yanlış anlamaktan gelir. Render, “DOM’a yazmak” değildir; React’in ekranı nasıl güncelleyeceğine karar verdiği bir hesaplama sürecidir.
İyi haber şu: Gereksiz render’ları azaltmak için sihirli bir eklentiye ihtiyacınız yok. Ne zaman render tetikleniyor, React “değişti” kararını nasıl veriyor ve hangi optimizasyonlar neyi çözüyor; bunları netleştirince performans şikâyetlerinin büyük kısmı sistematik olarak çözülür.
Bu rehberde “reconciliation”, “commit”, “memoization” gibi kavramları sade bir çerçeveyle ele alıp, gerçekçi örneklerle ilerleyeceğiz. Uygulamalı alıştırmalar ve performans inceleme adımları için react eğitimi sayfasına da göz atabilirsiniz.

Render sürecini doğru tanımlamak ve çerçevelemek
React’te “render”, bileşenin UI çıktısını üretme işidir. JSX’in fonksiyon çağrısı gibi çalıştığını düşünün: State/props değiştiğinde bileşen fonksiyonu tekrar çalışır, React de yeni UI ağacını hesaplar. Bu aşama, “ne gösterilmeli?” sorusunu cevaplar.
Sonra React, yeni ağaç ile eski ağaç arasındaki farkı bulur ve gerekli değişiklikleri uygular. Burada iki kritik kavram ayrılır: render phase ve commit phase. Render phase daha çok hesaplama ve karşılaştırma iken, commit phase ekrana yazma (DOM/Native) kısmıdır.
Render ve commit ayrımını netleştirerek konuşmak
Bir bileşen “render oldu” denildiğinde, her zaman DOM’da bir değişiklik olmuş olmayabilir. React, render phase’te yeni çıktıyı üretir; eğer gerçek bir fark yoksa commit daha hafif olur. Bu ayrımı bilmek, “neden render sayısı yüksek ama ekran aynı?” sorusunu açıklamayı sağlar.
Reconciliation mantığını basitleştirerek izlemek
Reconciliation, React’in “eski UI ağacı” ile “yeni UI ağacı” arasındaki farkı bulma sürecidir. Key’ler, bileşen kimliği ve props değişimleri burada belirleyicidir. Yanlış key kullanımı ya da gereksiz yeniden yaratılan bileşenler, diff maliyetini büyütür ve zincirleme güncellemeler doğurur.
Render tetikleyicilerini doğru tanımlamak ve izlemek
Gereksiz render azaltmanın ilk adımı, render’ı neyin tetiklediğini sınıflandırmaktır. React’te en yaygın tetikleyiciler: state güncellemesi, props değişimi, context güncellemesi ve parent bileşenin yeniden render olmasıdır.
State güncellemelerini kontrollü kullanmak ve sınırlandırmak
State değişince bileşen yeniden çalışır. Ancak state’i “gereken en küçük alanda” tutmak önemlidir. Çok üst seviyede tutulan state, geniş bir alt ağacı gereksiz yere hareketlendirir. Ayrıca aynı değer tekrar set edilse bile (özellikle obje/array referansı değişiyorsa) yeniden render tetiklenebilir.
Props referanslarını stabil tutmak ve sadeleştirmek
Props olarak geçirilen obje, array ya da inline fonksiyonlar her render’da yeni referans üretir. Child bileşen props “değişti” diye yeniden çalışır. Çözüm çoğu zaman props tasarımını sade tutmak ve referansları stabil kılmaktır (useMemo/useCallback gibi).
- Inline object yerine memoize edilmiş obje ile ilerlemek
- Inline function yerine useCallback ile fonksiyonu sabitlemek
- Gereksiz props taşımayı bırakıp veri sınırı çizmek
- Context değerini bölerek tüketimi küçültmek
Memoization yaklaşımını doğru seçmek ve uygulamak
Memoization, her şeyi otomatik hızlandırmaz; yanlış kullanılırsa kod karmaşasını artırır. Temel fikir, “aynı girdiler varsa aynı çıktıyı tekrar hesaplama”dır. React tarafında bunun üç yaygın aracı var: React.memo, useMemo ve useCallback.
React.memo kullanımını ölçerek yerleştirmek
React.memo, props eşitliği bozulmadıkça bileşenin yeniden render olmasını engelleyebilir. Ancak props olarak her seferinde yeni referanslar geçiyorsanız memo’nun faydası düşer. Önce tetikleyiciyi bulup, sonra memo ile kapatmak daha sağlıklı olur.
useMemo ve useCallback ile referansı sabitlemek
useMemo, pahalı hesaplamaları ya da prop olarak geçilecek objeleri sabitlemek için; useCallback ise fonksiyon referansını sabitlemek için kullanılır. Burada en önemli nokta dependency listesini doğru kurmaktır; aksi halde stale (eski) veriyle çalışmak gibi hatalar oluşur.
import React, { useCallback, useMemo, useState } from "react";
const Row = React.memo(function Row({ item, onSelect }) {
console.log("Row render:", item.id);
return (
<button onClick={() => onSelect(item.id)}>
{item.title}
</button>
);
});
export default function ListPage({ rawItems }) {
const [query, setQuery] = useState("");
const items = useMemo(() => {
const q = query.trim().toLowerCase();
if (!q) return rawItems;
return rawItems.filter(x => x.title.toLowerCase().includes(q));
}, [rawItems, query]);
const onSelect = useCallback((id) => {
console.log("selected:", id);
}, []);
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
{items.map((item) => (
<Row key={item.id} item={item} onSelect={onSelect} />
))}
</div>
);
}Bu örnekte iki hedef var: Filtre hesaplamasını gereksiz yere tekrarlamamak ve Row bileşenine her render’da yeni fonksiyon göndermemek. React.memo tek başına yetmez; props referansları da stabil olmalı.

Context ve state mimarisini sadeleştirmek ve bölmek
Bir uygulamada performans şikâyetlerinin büyük kısmı “her şey tek context’te” ya da “tek store’dan her yer besleniyor” gibi geniş kapsamlı güncelleme alanlarından gelir. Context güncellemesi, o context’i tüketen bileşenleri tetikler; dolayısıyla context tasarımında sınır çizmek kritik olur.
Context değerini bölerek tüketimi küçültmek
Tek bir “AppContext” içinde kullanıcı, tema, sepet ve izinler gibi birçok değer varsa; küçük bir değişim tüm tüketicileri etkileyebilir. Çözüm, context’i alanlara ayırmak ve mümkünse sadece ihtiyaç duyulan alt ağaca provider koymaktır. Böylece render dalgasını daraltmak mümkün olur.
Derived state kullanımını azaltarak karmaşayı önlemek
“State içinde state” gibi durumlar (örneğin filtrelenmiş listeyi ayrıca state’te tutmak) çakışmaları artırır. Çoğu derived veri, render sırasında hesaplanabilir ve useMemo ile optimize edilebilir. Bu yaklaşım, hem hata riskini azaltır hem de güncellemeleri daha öngörülebilir kılar.
Key ve liste yönetimini doğru kurgulamak ve stabil tutmak
Listelerdeki key stratejisi, React’in hangi elemanın “aynı” olduğunu anlaması için hayati önem taşır. Yanlış key, React’in elemanları yeniden yaratmasına, input odaklarının kaymasına ve gereksiz DOM işlemlerine yol açabilir.
Index yerine kalıcı kimlik kullanarak eşleşmek
Index key kullanımı; sıralama değiştiğinde, ekleme/çıkarma olduğunda eleman kimliğini bozar. Sonuç: React, elemanları yanlış eşleştirir ve “gereksiz render” hissi artar. Kalıcı ve benzersiz bir id ile eşleşmek daha güvenilir olur.
Liste bileşenini bölerek güncellemeyi daraltmak
Çok büyük listelerde tek bileşen içinde hem filtre hem satır render’ı yönetmek, değişimi genişletir. Listeyi “kontrol paneli + liste gövdesi + satır” olarak bölmek ve satırı memoize etmek, güncelleme alanını daraltmaya yardımcı olur. Ayrıca sanallaştırma (virtualization) gibi teknikler, DOM maliyetini düşürmekte etkilidir.
Profiling alışkanlığını kurmak ve kök nedeni bulmak
“Memo ekledim hızlandı mı?” sorusunun yanıtını tahminle değil, ölçümle vermek gerekir. React DevTools Profiler, hangi bileşenin ne kadar sürdüğünü ve neden render aldığını görmenize yardım eder. Burada hedef, en çok zaman harcayan ve en sık tetiklenen noktaları bulmaktır.
Profiler çıktısını okuyarak aksiyon almak
Profiler’da “Commit duration” ve bileşen ağaçları üzerinden ilerleyip, render zincirini takip edebilirsiniz. “Neden render oldu?” bilgisini yorumlayınca, gerçek çözüm genellikle basit çıkar: stabil props, daha küçük context, doğru key ya da daha iyi state sınırı.
Günlük geliştirmede ölçümlemeyi rutine eklemek
Her performans sorununda tüm uygulamayı profil etmek zorunda değilsiniz. Lokal bir sayfayı izole edip, render log’ları ve Profiler ile küçük bir döngü kurmak yeterli olur. Aşağıdaki mini yardımcı, hangi prop değişince yeniden render olduğunu yakalamayı kolaylaştırır.
import { useEffect, useRef } from "react";
export function useWhyDidYouUpdate(name, props) {
const prev = useRef(props);
useEffect(() => {
const changed = Object.keys({ ...prev.current, ...props }).reduce((acc, key) => {
if (prev.current[key] !== props[key]) acc[key] = { from: prev.current[key], to: props[key] };
return acc;
}, {});
if (Object.keys(changed).length) {
console.log("[why-did-you-update]", name, changed);
}
prev.current = props;
});
}Bu yardımcıyı kritik bileşenlerde kısa süreli kullanıp “hangi prop referansı değişiyor?” sorusuna net yanıt alabilirsiniz. Sonrasında gereksiz render’ı kök neden üzerinden azaltmak çok daha hızlı ilerler.

Kapanış: Gereksiz render azaltmak için önce React’in render ve commit sürecini anlamak, sonra tetikleyicileri sınıflandırmak gerekir. Ardından memoization’ı ölçerek uygulamak, context ve state sınırlarını daraltmak, key stratejisini doğru kurgulamak ve profiling’i rutinleştirmek hızlı kazanımlar sağlar. Pratik egzersiz ve örnek projelerle ilerlemek isterseniz react eğitimi içeriği bu konuları adım adım pekiştirmenize yardımcı olur.


