React'te bileşenlerin gereksiz yere yeniden render edilmesi, özellikle büyük listeler veya karmaşık alt bileşen ağaçlarında performans sorunlarına yol açabilir. useCallback ve useMemo hook'ları, bu tür durumlarda değerleri ve fonksiyonları önbelleğe alarak gereksiz render'ları engellemek için kullanılır. Peki bu hook'ları her yerde kullanmak doğru mu? İşte doğru kullanım stratejileri ve dikkat edilmesi gereken noktalar.
useCallback Hook'u Nedir ve Ne Zaman Kullanılmalıdır?
useCallback, bir fonksiyonun referansını bağımlılıklar değişmediği sürece koruyan bir hook'tur. React'te, her render işlemi sırasında bileşen içinde tanımlanan fonksiyonlar yeniden oluşturulur. Bu, alt bileşenlere prop olarak geçilen fonksiyonların referanslarının her seferinde değişmesi anlamına gelir. Eğer alt bileşen React.memo ile sarmalanmışsa, prop referansı değiştiği için yeniden render edilir. useCallback bu durumu engeller.
Ne zaman kullanılmalı?
- Fonksiyonları
React.memoile optimize edilmiş alt bileşenlere prop olarak geçiriyorsanız. - Fonksiyon,
useEffectveya başka bir hook'un bağımlılık dizisinde yer alıyorsa (bağımlılıklar sabit kaldığında gereksiz effect tetiklenmesini önlemek için). - Fonksiyon oluşturma maliyeti yüksekse (örneğin, kapsamındaki değişken sayısı fazlaysa).
Ancak, useCallback'in kendisinin de bir maliyeti vardır. Bağımlılık dizisini kontrol eder ve gereksiz kullanımı performansı iyileştirmez, aksine hafif bir memory ve CPU yükü getirir. Bu nedenle, kullanmadan önce gerçekten bir render sorunu yaşadığınızdan emin olun. React ekibi, React useReducer Hook ile Karmaşık State Yönetimi yazımızda da belirttiği gibi, state yönetimi ve render optimizasyonu birbiriyle yakından ilişkilidir.
useMemo ile Değer Önbellekleme Nasıl Yapılır?
useMemo, bir hesaplamanın sonucunu bağımlılıklar değişmediği sürece önbellekte tutar. Karmaşık hesaplamalar (örneğin büyük bir listenin filtrelenmesi, sıralanması veya matematiksel işlemler) her render'da tekrarlanırsa performans düşer. useMemo bu hesaplamaları yalnızca bağımlılıklar değiştiğinde yapar.
Ne zaman kullanılmalı?
- Pahalı hesaplamalar (O(n^2) veya daha yüksek karmaşıklık) içeren değerler varsa.
- Hesaplama sonucu alt bileşenlere prop olarak geçiliyorsa ve referans kararlılığı önemliyse.
- Referans kararlılığı sağlamak için (örn. objeler veya diziler) – ancak bu durumda genellikle useMemo kullanmak doğrudur, çünkü referans eşitliği kontrol edilir.
useMemo, yalnızca sonuç değerini önbelleğe alır. Fonksiyonun kendisini önbelleğe almak için useCallback kullanılır. İkisi farklı amaçlara hizmet eder. Ayrıca, useMemo içinde yan etkiler (effect) gerçekleştirmeyin; bu iş için useEffect kullanılmalıdır.
useCallback ve useMemo Kullanırken Sık Yapılan Hatalar
- Her yerde kullanmak: Küçük ve hızlı hesaplamalar veya basit callback'ler için useCallback/useMemo kullanmak gereksizdir. İlk olarak
React.memoile alt bileşenlerin prop referanslarını kontrol edin. - Bağımlılık dizisini yanlış belirlemek: Bağımlılıkların eksik veya fazla olması, ya hatalara (stale closure) ya da gereksiz rekalkülasyonlara yol açar.
eslint-plugin-react-hookskullanarak bağımlılıkları doğru ayarlayın. - Ölçüm yapmadan optimizasyon: Herhangi bir performans sorunu yaşamıyorsanız, useCallback/useMemo eklemek size fayda sağlamaz. React Developer Tools ile render'ları profillemek en doğru yaklaşımdır. Daha önceki React useState Hook ile State Yönetimi yazımızda da belirttiğimiz gibi, state güncellemeleri render'ları tetikler; gereksiz render'ları engellemek için bu hook'lar doğru kullanılmalıdır.
- Unutulan bağımlılıklar: Fonksiyon içinde kullanılan değişkenleri bağımlılık dizisine eklemeyi unutmayın. Bu, eski değerlere erişmeye (stale closure) neden olur.
Performans Testi: useCallback/useMemo Gerçekten İşe Yarıyor mu?
Bir liste bileşeni düşünelim: 1000 öğeyi sıralayıp render ediyor. Sıralama işlemi her tuş vuruşunda tekrarlanırsa, kullanıcı deneyimi kötüleşir. useMemo ile sıralama sonucunu önbelleğe almak, yalnızca liste verisi veya sıralama kriteri değiştiğinde hesaplamayı yapar. Aynı şekilde, her satır için bir onClick fonksiyonunu useCallback ile sarmalamak, satır bileşenlerinin gereksiz render edilmesini engeller.
Örnek kod:
const sortedList = useMemo(() => {
return [...items].sort(sortFn);
}, [items, sortFn]);
const handleClick = useCallback((id) => {
// işlem
}, [dependency]);
Bu optimizasyonlar, özellikle büyük listeler veya sık güncellenen verilerle çalışırken belirgin bir fark yaratır. Ancak, useEffect cleanup işlemleri gibi diğer optimizasyonları da unutmayın; React useEffect Cleanup Fonksiyonu ile Bellek Sızıntılarını Önleme yazımız da bu konuda önemli ipuçları sunar.
useCallback ve useMemo Alternatifleri: Ne Zaman Uzak Durmalıyız?
Her iki hook da React'ın built-in araçlarıdır, ancak her sorunun cevabı değildir. Bazı durumlarda, state'i daha iyi organize etmek (örneğin React useReducer kullanarak) veya bileşen yapısını değiştirmek (örneğin, alt bileşenleri daha küçük parçalara bölmek) daha iyi sonuç verebilir. Ayrıca, useMemo içinde dönüştürmeler yapmak yerine, veriyi kaynakta işlemek (backend'de sıralama yapmak gibi) de düşünülebilir.
Son olarak, useCallback ve useMemo'yu kullanırken kodu gereksiz yere karmaşık hale getirmemeye dikkat edin. Kullanıcıya gerçek bir performans artışı sağlamıyorsa, okunabilirlikten ödün vermek anlamsızdır.
Sık Sorulan Sorular
useCallback ve useMemo arasındaki fark nedir?
useCallback bir fonksiyonu, useMemo ise bir değeri (genellikle bir hesaplama sonucunu) önbelleğe alır. useCallback, fonksiyon referansını sabit tutarken; useMemo, bağımlılıklar değişmediği sürece hesaplamayı tekrarlamaz.
useCallback her fonksiyon için kullanılmalı mı?
Hayır. useCallback'in getirdiği ek yük, basit ve hızlı oluşturulan fonksiyonlar için onu kullanmaya değmez. Yalnızca React.memo ile optimize edilmiş alt bileşenlere geçen veya bağımlılık dizilerinde yer alan fonksiyonlar için düşünülmelidir.
useMemo pahalı hesaplamalar dışında kullanılabilir mi?
Evet, referans kararlılığı sağlamak için de kullanılabilir. Örneğin, objeler veya diziler her render'da yeniden oluşturulur; useMemo ile bunları önbelleğe alarak alt bileşenlerde gereksiz render'ları önleyebilirsiniz.
useCallback/useMemo performansı her zaman artırır mı?
Hayır. Yanlış kullanıldığında (örneğin bağımlılıkların eksik verilmesi), hatalara yol açar ve performansı düşürebilir. Her zaman önce profilleme yapmalı, gerçek bir darboğaz olduğunda kullanmalısınız.
React.memo ile useCallback birlikte nasıl çalışır?
React.memo, prop referanslarını yüzeysel olarak karşılaştırır. Eğer alt bileşene geçen bir callback her render'da yeniden oluşturuluyorsa, React.memo bu değişikliği algılar ve bileşeni yeniden render eder. useCallback, callback referansını sabit tutarak bu durumu engeller.






