- Gereksiz render nedir, ne zaman sorun olur?
- Önce yapıyı düzeltin: durumu aşağı alın, children kullanın
- memo: props değişmediyse yeniden render etme
- useCallback ve useMemo: referansı sabit tutmak
- Memoization neden işe yaramaz? React Compiler
- Ölçüm odaklı kontrol listesi ve sık hatalar
- Bu beceriyi Mindset programlarında nerede çalışırsınız?
- Sık sorulan sorular
React performans optimizasyonu: memo, useMemo ve useCallback ne zaman gerekir
React'ta gereksiz render'ı önleme: önce ölçüm, durumu aşağı alma, memo, useMemo ve useCallback ile referans kararlılığı, işe yaramadığı durumlar.
Gereksiz render nedir, ne zaman sorun olur?
React'te bir bileşenin durumu değiştiğinde o bileşen ve altındaki tüm çocuk bileşenler varsayılan olarak yeniden render edilir. Render, bileşen fonksiyonunun yeniden çalışması demektir; ekranın yeniden çizilmesi değildir. React yeni çıktıyı eskisiyle karşılaştırır ve yalnızca fark varsa DOM'u günceller. Yani çıktısı değişmeyen bir çocuğun yeniden render olması çoğu zaman görünmez ve ucuzdur.
"Gereksiz render" bu yüzden ancak şu koşullar birlikte olduğunda sorundur: bileşen aynı girdilerle sık yeniden render oluyor ve render işi pahalı (büyük liste, ağır hesap, çok sayıda çocuk). React belgesi de bunu söyler: memo yalnızca bir bileşen sık ve aynı props ile yeniden render oluyor ve render mantığı pahalıysa değerlidir; yeniden render sırasında hissedilir bir gecikme yoksa gereksizdir.
Bu nedenle optimizasyona başlamadan önce ölçün. React Developer Tools'taki Profiler, hangi bileşenin ne sıklıkla ve ne kadar sürede render olduğunu gösterir. Kullanıcının hissetmediği bir render'ı memo ile "çözmek" kodu karmaşıklaştırmaktan başka bir şey yapmaz.
Önce yapıyı düzeltin: durumu aşağı alın, children kullanın
En ucuz çözüm çoğu zaman memoization değil yapıdır. React belgesi şu alışkanlıkları önerir:
- Durumu gereğinden yukarıda tutmayın. Yalnızca bir girdi kutusunu ilgilendiren durum, tüm sayfanın bileşeninde değil, o kutuyu içeren küçük bileşende tutulursa yazı yazarken yalnızca o bileşen render olur.
- JSX'i children olarak kabul edin. Durumu tutan sarmalayıcı bileşen, dışarıdan gelen children'ı yeniden oluşturmaz; sarmalayıcının durumu değişince children render edilmez.
- Render'ı saf tutun ve gereksiz Effect zincirlerinden kaçının. Bir Effect'in durum güncelleyip yeni bir render tetiklemesi ek maliyet doğurur.
Örneğin sürekli güncellenen bir arama kutusu ile yanındaki ağır bir ürün tablosu aynı bileşende duruyorsa, arama kutusunu ayrı bir bileşene taşımak tabloyu her tuşta render etmekten kurtarır. Bu değişiklik hiçbir hook gerektirmez.
memo: props değişmediyse yeniden render etme
Yapı düzeltmesi yetmezse memo devreye girer. memo ile sarılan bileşen, ebeveyni yeniden render olsa bile props'ları değişmediyse genellikle yeniden render edilmez:
const ProductRow = memo(function ProductRow({ product, onSec }) { return <li onClick={() => onSec(product.id)}>{product.ad}</li>; });
React her prop'u Object.is ile karşılaştırır (yüzeysel karşılaştırma). Metin ve sayılar değerle karşılaştırılır, ama nesneler, diziler ve fonksiyonlar referansla. İçeriği aynı olsa bile her render'da yeniden oluşturulan bir nesne ya da fonksiyon, değişmiş bir prop sayılır ve memo'yu etkisiz bırakır.
memo bir garanti değil, performans iyileştirmesidir: React gerekli gördüğünde yine de render edebilir. Ayrıca memo'lu bileşen kendi durumu değiştiğinde ve kullandığı bir context değiştiğinde yine yeniden render olur. Bu yüzden memo olmadan çalışmayan bir kod, asıl sorunun başka yerde olduğunu gösterir.
useCallback ve useMemo: referansı sabit tutmak
memo'nun işe yaraması için çocuğa verilen props'ların referansı render'lar arasında sabit kalmalıdır. Bunun için şu hook'lar kullanılır:
- useCallback fonksiyonu, bağımlılıkları değişmedikçe aynı referansla saklar.
- useMemo bir hesabın sonucunu (nesne, dizi, türetilmiş değer) bağımlılıkları değişmedikçe saklar.
Liste örneği:
function ProductList({ products }) { const [arama, setArama] = useState(""); const [secili, setSecili] = useState(null);
const secimiYap = useCallback((id) => setSecili(id), []);
const gorunenler = useMemo( () => products.filter(u => u.ad.includes(arama)), [products, arama] );
return ( <ul> {gorunenler.map(u => ( <ProductRow key={u.id} product={u} onSec={secimiYap} /> ))} </ul> ); }
secimiYap sabit olduğu için ProductRow satırları, arama kutusu her değiştiğinde değil, yalnızca kendi product nesnesi değiştiğinde render olur. useMemo burada filtrelemeyi yalnızca products ya da arama değiştiğinde yapar. React belgesi, nesne yerine çocuğun gerçekten ihtiyaç duyduğu ilkel değerleri geçmenin (örneğin ad ve yaş ayrı prop olarak) çoğu zaman nesneyi useMemo ile sabitlemekten daha sade olduğunu belirtir.
Memoization neden işe yaramaz? React Compiler
Beklediğiniz iyileşme gelmiyorsa şu nedenlere bakın:
- Prop'lardan biri her render'da yeni referans alıyor: satır içi nesne, dizi ya da ok fonksiyonu.
- Bağımlılık dizisinde her render'da değişen bir değer var; useCallback ve useMemo her seferinde yeniden üretir.
- Bileşen bir context'i okuyor. Context değeri değiştiğinde memo onu engellemez; context'i okuyan bileşen yine render olur.
- memo özel karşılaştırma fonksiyonuyla kullanılıyor ve bazı props (özellikle fonksiyonlar) karşılaştırmaya katılmıyor. Eski state'i gören işleyiciler ortaya çıkabilir; özel karşılaştırma yazarsanız tüm props'u karşılaştırın ve derin eşitlik kontrolünden kaçının.
- Props her zaman farklı; bu durumda memo tümüyle gereksizdir.
React Compiler etkinleştirilmiş projelerde, React belgesine göre çoğunlukla React.memo'ya ihtiyaç kalmaz; derleyici yeniden render'ı otomatik optimize eder ve ara değerleri de belleğe alır. Projenizde derleyicinin açık olup olmadığını öğrenin; açıksa elle yazılmış memoization'ı gözden geçirip sadeleştirmek gerekebilir.
Ölçüm odaklı kontrol listesi ve sık hatalar
Bir performans şikâyetinde şu sırayı izleyin:
- Sorunu yeniden üretin: hangi etkileşim yavaş, hangi bileşen hissedilir ölçüde geç render oluyor?
- Profiler ile hangi bileşenlerin neden render olduğuna bakın.
- Önce yapıyı düzeltin: durumu aşağı alın, children kullanın.
- Hâlâ gerekiyorsa pahalı bileşeni memo ile sarın ve props referanslarını sabitleyin.
- Değişikliği tekrar ölçün. İyileşme yoksa memoization'ı geri alın.
Sık hatalar: her bileşeni ve her fonksiyonu önlem olarak memo ve useCallback ile sarmak; bağımlılık dizisini lint uyarısını susturarak yazmak; ölçmeden optimize etmek; listelerde key olarak dizi sırasını kullanmak ve öğeler yeniden sıralanınca durumun karışması.
Bu beceriyi Mindset programlarında nerede çalışırsınız?
React İleri Seviye: Performans ve Durum Yönetimi programı bu konunun asıl adresidir. "React Render Modeli" modülü render'ın nasıl çalıştığını, "Memoization ve Referans Kararlılığı" modülü memo, useMemo ve useCallback'in doğru kullanımını, "Liste Performansı, Paket ve Ölçüm" modülü ise ölçmeyi ele alır. React ile çalışan ve yavaşlayan arayüzlerle uğraşan geliştiriciler ile ön yüz ekip liderleri için uygundur.
Modern Web Geliştirme, Frontend (React) programındaki "Performans Optimizasyonu" modülü temel düzeyde aynı konuyu tanıtır. Kurumsal ekiplerde ortak bir performans inceleme yöntemi (önce ölç, sonra düzelt) kod inceleme standardına dönüştürülebilir.
İlgili Mindset programı
React İleri Seviye: Performans ve Durum Yönetimi
Sık sorulan sorular
useMemo ile useCallback arasındaki fark nedir?
useMemo bir hesabın sonucunu, useCallback ise fonksiyonun kendisini bağımlılıklar değişmedikçe saklar. Pratikte useCallback, fonksiyonu döndüren bir useMemo'dur. Bu hook'lar yalnızca referans kararlılığı gerektiğinde, örneğin memo'lu bir çocuğa prop geçerken ya da bir Effect'in bağımlılığı olarak anlamlıdır.
Her bileşeni memo ile sarmak iyi bir fikir mi?
Hayır. memo her render'da props karşılaştırması yapar ve bu da bir maliyettir. Props sık değişiyorsa ya da render ucuzsa fayda sağlamaz, kodu da karmaşıklaştırır. Önce Profiler ile yavaş bileşeni bulun, yapıyı düzeltin, gerekirse yalnız o bileşene uygulayın.
Liste performansı için memo yeterli mi?
Çoğu zaman yetmez. Çok uzun listelerde ekranda görünen öğeleri çizen sanallaştırma gibi teknikler, memo'dan daha büyük kazanç sağlar. Ayrıca satırlara geçen fonksiyon ve nesnelerin referansını sabit tutmak gerekir; aksi halde memo'lu satırlar yine yeniden render olur.
React Compiler memo yazma ihtiyacını ortadan kaldırır mı?
React belgesine göre derleyici etkinleştirildiğinde genellikle React.memo'ya ihtiyaç duymazsınız, çünkü derleyici yeniden render'ı otomatik optimize eder. Derleyici projede açık değilse memoization hâlâ elle yönetilir. Hangisinin geçerli olduğunu proje yapılandırmasından kontrol edin.
İlgili rehberler
İlgili eğitimler
Kategori: Yazılım Geliştirme