useMemo, useCallback ve React.memo kullanarak React uygulama performansını optimize etmeye yönelik kapsamlı bir kılavuz. Gereksiz yeniden işlemeleri önlemeyi ve kullanıcı deneyimini iyileştirmeyi öğrenin.
React Performans Optimizasyonu: useMemo, useCallback ve React.memo'da Ustalaşmak
React, kullanıcı arayüzleri oluşturmak için popüler bir JavaScript kütüphanesidir ve bileşen tabanlı mimarisi ve bildirimsel stili ile bilinir. Ancak, uygulamalar karmaşıklık açısından büyüdükçe, performans bir sorun haline gelebilir. Bileşenlerin gereksiz yere yeniden işlenmesi, yavaş performansa ve kötü bir kullanıcı deneyimine yol açabilir. Neyse ki, React, useMemo
, useCallback
ve React.memo
dahil olmak üzere performansı optimize etmek için çeşitli araçlar sunar. Bu kılavuz, yüksek performanslı React uygulamaları oluşturmanıza yardımcı olmak için pratik örnekler ve eyleme dönüştürülebilir bilgiler sağlayarak bu teknikleri derinlemesine incelemektedir.
React Yeniden İşlemelerini Anlamak
Optimizasyon tekniklerine dalmadan önce, yeniden işlemelerin React'te neden gerçekleştiğini anlamak çok önemlidir. Bir bileşenin durumu veya özellikleri değiştiğinde, React o bileşenin ve potansiyel olarak alt bileşenlerinin yeniden işlenmesini tetikler. React, gerçek DOM'u verimli bir şekilde güncellemek için sanal bir DOM kullanır, ancak aşırı yeniden işlemeler, özellikle karmaşık uygulamalarda performansı etkileyebilir. Ürün fiyatlarının sık sık güncellendiği küresel bir e-ticaret platformu hayal edin. Optimizasyon olmadan, küçük bir fiyat değişikliği bile tüm ürün listesinde yeniden işlemeleri tetikleyebilir ve kullanıcı taramasını etkileyebilir.
Bileşenler Neden Yeniden İşlenir?
- Durum Değişiklikleri: Bir bileşenin durumu
useState
veyauseReducer
kullanılarak güncellendiğinde, React bileşeni yeniden işler. - Özellik Değişiklikleri: Bir bileşen, üst bileşeninden yeni özellikler alırsa, yeniden işlenir.
- Üst Yeniden İşlemeler: Bir üst bileşen yeniden işlendiğinde, özelliklerinin değişip değişmediğine bakılmaksızın, alt bileşenleri de varsayılan olarak yeniden işlenir.
- Bağlam Değişiklikleri: Bir React Bağlamı tüketen bileşenler, bağlam değeri değiştiğinde yeniden işlenir.
Performans optimizasyonunun amacı, gereksiz yeniden işlemeleri önlemek ve bileşenlerin yalnızca verileri gerçekten değiştiğinde güncellenmesini sağlamaktır. Borsa analizi için gerçek zamanlı veri görselleştirmeyi içeren bir senaryo düşünün. Grafik bileşenleri her küçük veri güncellemesinde gereksiz yere yeniden işlenirse, uygulama yanıt vermez hale gelir. Yeniden işlemelerin optimize edilmesi, sorunsuz ve duyarlı bir kullanıcı deneyimi sağlayacaktır.
useMemo'yu Tanıtıyoruz: Pahalı Hesaplamaları Not Alma
useMemo
, bir hesaplamanın sonucunu not alan bir React kancasıdır. Not alma, pahalı fonksiyon çağrılarının sonuçlarını depolayan ve aynı girdiler tekrar oluştuğunda bu sonuçları yeniden kullanan bir optimizasyon tekniğidir. Bu, fonksiyonu gereksiz yere yeniden çalıştırma ihtiyacını önler.
useMemo Ne Zaman Kullanılır?
- Pahalı Hesaplamalar: Bir bileşenin, özelliklerine veya durumuna bağlı olarak hesaplama açısından yoğun bir hesaplama gerçekleştirmesi gerektiğinde.
- Referans Eşitliği: Yeniden işlenip işlenmeyeceğini belirlemek için referans eşitliğine dayanan bir alt bileşene bir özellik olarak bir değer geçirilirken.
useMemo Nasıl Çalışır?
useMemo
iki argüman alır:
- Hesaplamayı gerçekleştiren bir fonksiyon.
- Bağımlılıklar dizisi.
Fonksiyon yalnızca dizideki bağımlılıklardan biri değiştiğinde yürütülür. Aksi takdirde, useMemo
önceden not alınmış değeri döndürür.
Örnek: Fibonacci Dizisini Hesaplama
Fibonacci dizisi, hesaplama açısından yoğun bir hesaplamanın klasik bir örneğidir. useMemo
kullanarak n. Fibonacci sayısını hesaplayan bir bileşen oluşturalım.
import React, { useState, useMemo } from 'react';
function Fibonacci({ n }) {
const fibonacciNumber = useMemo(() => {
console.log('Fibonacci Hesaplanıyor...'); // Hesaplamanın ne zaman çalıştığını gösterir
function calculateFibonacci(num) {
if (num <= 1) {
return num;
}
return calculateFibonacci(num - 1) + calculateFibonacci(num - 2);
}
return calculateFibonacci(n);
}, [n]);
return Fibonacci({n}) = {fibonacciNumber}
;
}
function App() {
const [number, setNumber] = useState(5);
return (
setNumber(parseInt(e.target.value))}
/>
);
}
export default App;
Bu örnekte, calculateFibonacci
fonksiyonu yalnızca n
özelliği değiştiğinde yürütülür. useMemo
olmadan, fonksiyon n
aynı kalsa bile, Fibonacci
bileşeninin her yeniden işlenmesinde yürütülürdü. Bu hesaplamanın küresel bir finansal panoda gerçekleştiğini hayal edin - piyasanın her hareketi tam bir yeniden hesaplamaya neden oluyor ve bu da önemli gecikmelere yol açıyor. useMemo
bunu önler.
useCallback'i Tanıtıyoruz: Fonksiyonları Not Alma
useCallback
, fonksiyonları not alan başka bir React kancasıdır. Her render'da yeni bir fonksiyon örneği oluşturulmasını önler; bu, özellikle geri aramaları alt bileşenlere özellik olarak geçirirken yararlı olabilir.
useCallback Ne Zaman Kullanılır?
- Geri Aramaları Özellik Olarak Geçirme:
React.memo
veyashouldComponentUpdate
kullanarak yeniden işlemeleri optimize eden bir alt bileşene bir fonksiyonu özellik olarak geçirirken. - Olay İşleyicileri: Alt bileşenlerin gereksiz yeniden işlemelerini önlemek için bir bileşen içinde olay işleyici fonksiyonları tanımlarken.
useCallback Nasıl Çalışır?
useCallback
iki argüman alır:
- Not alınacak fonksiyon.
- Bağımlılıklar dizisi.
Fonksiyon yalnızca dizideki bağımlılıklardan biri değiştiğinde yeniden oluşturulur. Aksi takdirde, useCallback
aynı fonksiyon örneğini döndürür.
Örnek: Bir Düğme Tıklamasını İşleme
Bir geri arama fonksiyonunu tetikleyen bir düğmeye sahip bir bileşen oluşturalım. Geri arama fonksiyonunu not almak için useCallback
kullanacağız.
import React, { useState, useCallback } from 'react';
function Button({ onClick, children }) {
console.log('Düğme yeniden işlendi'); // Düğmenin ne zaman yeniden işlendiğini gösterir
return ;
}
const MemoizedButton = React.memo(Button);
function App() {
const [count, setCount] = useState(0);
const handleClick = useCallback(() => {
console.log('Düğme tıklandı');
setCount((prevCount) => prevCount + 1);
}, []); // Boş bağımlılık dizisi, fonksiyonun yalnızca bir kez oluşturulduğu anlamına gelir
return (
Sayı: {count}
Artır
);
}
export default App;
Bu örnekte, bağımlılık dizisi boş olduğundan handleClick
fonksiyonu yalnızca bir kez oluşturulur. App
bileşeni count
durum değişikliği nedeniyle yeniden işlendiğinde, handleClick
fonksiyonu aynı kalır. React.memo
ile sarılmış MemoizedButton
bileşeni, yalnızca özellikleri değişirse yeniden işlenir. onClick
özelliği (handleClick
) aynı kaldığı için, Button
bileşeni gereksiz yere yeniden işlenmez. Etkileşimli bir harita uygulaması hayal edin. Bir kullanıcı her etkileşimde bulunduğunda, düzinelerce düğme bileşeni etkilenebilir. useCallback
olmadan, bu düğmeler gereksiz yere yeniden işlenir ve bu da gecikmeli bir deneyim yaratır. useCallback
kullanmak daha sorunsuz bir etkileşim sağlar.
React.memo'yu Tanıtıyoruz: Bileşenleri Not Alma
React.memo
, fonksiyonel bir bileşeni not alan daha yüksek sıralı bir bileşendir (HOC). Özellikleri değişmediyse bileşenin yeniden işlenmesini önler. Bu, sınıf bileşenleri için PureComponent
'e benzer.
React.memo Ne Zaman Kullanılır?
- Saf Bileşenler: Bir bileşenin çıktısı yalnızca özelliklerine bağlıysa ve kendi durumu yoksa.
- Pahalı İşleme: Bir bileşenin işleme süreci hesaplama açısından pahalı olduğunda.
- Sık Yeniden İşlemeler: Bir bileşen, özellikleri değişmemiş olsa bile sık sık yeniden işlendiğinde.
React.memo Nasıl Çalışır?
React.memo
, fonksiyonel bir bileşeni sarar ve önceki ve sonraki özellikleri yüzeysel olarak karşılaştırır. Özellikler aynıysa, bileşen yeniden işlenmez.
Örnek: Bir Kullanıcı Profilini Görüntüleme
Bir kullanıcı profilini görüntüleyen bir bileşen oluşturalım. Kullanıcının verileri değişmediyse gereksiz yeniden işlemeleri önlemek için React.memo
kullanacağız.
import React from 'react';
function UserProfile({ user }) {
console.log('UserProfile yeniden işlendi'); // Bileşenin ne zaman yeniden işlendiğini gösterir
return (
Ad: {user.name}
E-posta: {user.email}
);
}
const MemoizedUserProfile = React.memo(UserProfile, (prevProps, nextProps) => {
// Özel karşılaştırma fonksiyonu (isteğe bağlı)
return prevProps.user.id === nextProps.user.id; // Yalnızca kullanıcı kimliği değişirse yeniden işle
});
function App() {
const [user, setUser] = React.useState({
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
});
const updateUser = () => {
setUser({ ...user, name: 'Jane Doe' }); // Adı değiştirme
};
return (
);
}
export default App;
Bu örnekte, MemoizedUserProfile
bileşeni yalnızca user.id
özelliği değişirse yeniden işlenir. user
nesnesinin diğer özellikleri değişse bile (örneğin, ad veya e-posta), kimlik farklı olmadığı sürece bileşen yeniden işlenmez. React.memo
içindeki bu özel karşılaştırma fonksiyonu, bileşenin ne zaman yeniden işleneceği üzerinde ince ayar yapılmasına olanak tanır. Sürekli güncellenen kullanıcı profillerine sahip bir sosyal medya platformu düşünün. React.memo
olmadan, bir kullanıcının durumunu veya profil resmini değiştirmek, temel kullanıcı ayrıntıları aynı kalsa bile profil bileşeninin tam olarak yeniden işlenmesine neden olur. React.memo
, hedeflenen güncellemelere olanak tanır ve performansı önemli ölçüde artırır.
useMemo, useCallback ve React.memo'yu Birleştirme
Bu üç teknik birlikte kullanıldığında en etkilidir. useMemo
pahalı hesaplamaları not alır, useCallback
fonksiyonları not alır ve React.memo
bileşenleri not alır. Bu teknikleri birleştirerek, React uygulamanızdaki gereksiz yeniden işleme sayısını önemli ölçüde azaltabilirsiniz.
Örnek: Karmaşık Bir Bileşen
Bu tekniklerin nasıl birleştirileceğini gösteren daha karmaşık bir bileşen oluşturalım.
import React, { useState, useCallback, useMemo } from 'react';
function ListItem({ item, onUpdate, onDelete }) {
console.log(`ListItem ${item.id} yeniden işlendi`); // Bileşenin ne zaman yeniden işlendiğini gösterir
return (
{item.text}
);
}
const MemoizedListItem = React.memo(ListItem);
function List({ items, onUpdate, onDelete }) {
console.log('Liste yeniden işlendi'); // Bileşenin ne zaman yeniden işlendiğini gösterir
return (
{items.map((item) => (
))}
);
}
const MemoizedList = React.memo(List);
function App() {
const [items, setItems] = useState([
{ id: 1, text: 'Öğe 1' },
{ id: 2, text: 'Öğe 2' },
{ id: 3, text: 'Öğe 3' },
]);
const handleUpdate = useCallback((id) => {
setItems((prevItems) =>
prevItems.map((item) =>
item.id === id ? { ...item, text: `Güncellendi ${item.text}` } : item
)
);
}, []);
const handleDelete = useCallback((id) => {
setItems((prevItems) => prevItems.filter((item) => item.id !== id));
}, []);
const memoizedItems = useMemo(() => items, [items]);
return (
);
}
export default App;
Bu örnekte:
useCallback
,handleUpdate
vehandleDelete
fonksiyonlarını not almak için kullanılır ve her render'da yeniden oluşturulmalarını önler.useMemo
,List
bileşeninin dizi referansı değişmediyse yeniden işlenmesini önlemek içinitems
dizisini not almak için kullanılır.React.memo
, özellikleri değişmediyse yeniden işlenmelerini önlemek içinListItem
veList
bileşenlerini not almak için kullanılır.
Bu tekniklerin birleşimi, bileşenlerin yalnızca gerektiğinde yeniden işlenmesini sağlayarak önemli performans iyileştirmelerine yol açar. Görev listelerinin sürekli olarak güncellendiği, silindiği ve yeniden sıralandığı büyük ölçekli bir proje yönetim aracı hayal edin. Bu optimizasyonlar olmadan, görev listesindeki herhangi bir küçük değişiklik, bir dizi yeniden işlemeyi tetikleyecek ve uygulamayı yavaş ve yanıt vermez hale getirecektir. useMemo
, useCallback
ve React.memo
'yu stratejik olarak kullanarak, uygulama karmaşık veriler ve sık güncellemelerle bile performanslı kalabilir.
Ek Optimizasyon Teknikleri
useMemo
, useCallback
ve React.memo
güçlü araçlar olsa da, React performansını optimize etmek için tek seçenek değiller. İşte dikkate alınması gereken birkaç ek teknik:
- Kod Bölme: Uygulamanızı isteğe bağlı olarak yüklenebilen daha küçük parçalara ayırın. Bu, ilk yükleme süresini azaltır ve genel performansı artırır.
- Tembel Yükleme: Bileşenleri ve kaynakları yalnızca ihtiyaç duyulduğunda yükleyin. Bu, özellikle resimler ve diğer büyük varlıklar için yararlı olabilir.
- Sanallaştırma: Büyük bir listenin veya tablonun yalnızca görünen bölümünü işleyin. Bu, büyük veri kümeleriyle uğraşırken performansı önemli ölçüde artırabilir.
react-window
vereact-virtualized
gibi kitaplıklar bu konuda yardımcı olabilir. - Sekme ve Kısma: Fonksiyonların yürütülme hızını sınırlayın. Bu, kaydırma ve yeniden boyutlandırma gibi olayları işlemek için yararlı olabilir.
- Değişmezlik: Kazara mutasyonlardan kaçınmak ve değişiklik algılamayı basitleştirmek için değişmez veri yapıları kullanın.
Optimizasyon için Küresel Hususlar
React uygulamalarını küresel bir kitle için optimize ederken, ağ gecikmesi, cihaz özellikleri ve yerelleştirme gibi faktörleri göz önünde bulundurmak önemlidir. İşte birkaç ipucu:
- İçerik Dağıtım Ağları (CDN'ler): Statik varlıkları kullanıcılarınıza daha yakın konumlardan sunmak için bir CDN kullanın. Bu, ağ gecikmesini azaltır ve yükleme sürelerini iyileştirir.
- Resim Optimizasyonu: Resimleri farklı ekran boyutları ve çözünürlükleri için optimize edin. Dosya boyutlarını küçültmek için sıkıştırma teknikleri kullanın.
- Yerelleştirme: Her kullanıcı için yalnızca gerekli dil kaynaklarını yükleyin. Bu, ilk yükleme süresini azaltır ve kullanıcı deneyimini iyileştirir.
- Uyarlanabilir Yükleme: Kullanıcının ağ bağlantısını ve cihaz özelliklerini algılayın ve uygulamanın davranışını buna göre ayarlayın. Örneğin, yavaş ağ bağlantıları veya eski cihazları olan kullanıcılar için animasyonları devre dışı bırakabilir veya görüntü kalitesini azaltabilirsiniz.
Sonuç
Sorunsuz ve duyarlı bir kullanıcı deneyimi sunmak için React uygulama performansını optimize etmek çok önemlidir. useMemo
, useCallback
ve React.memo
gibi tekniklerde uzmanlaşarak ve küresel optimizasyon stratejilerini göz önünde bulundurarak, çeşitli bir kullanıcı tabanının ihtiyaçlarını karşılamak için ölçeklenebilen yüksek performanslı React uygulamaları oluşturabilirsiniz. Performans darboğazlarını belirlemek ve bu optimizasyon tekniklerini stratejik olarak uygulamak için uygulamanızın profilini çıkarmayı unutmayın. Erken optimizasyon yapmayın - en önemli etkiyi elde edebileceğiniz alanlara odaklanın.
Bu kılavuz, React performans optimizasyonlarını anlamak ve uygulamak için sağlam bir temel sağlar. React uygulamaları geliştirmeye devam ederken, performansa öncelik vermeyi ve kullanıcı deneyimini iyileştirmenin yeni yollarını sürekli olarak aramayı unutmayın.