React Native uygulamalarınızın yavaş çalışmasından mı şikayetçiniz? Ekran geçişleri, liste kaydırmaları veya buton tepkime sürelerindeki yavaşlamalar kullanıcı deneyimini olumsuz etkileyebilir. Bu makale, özellikle gereksiz render’lardan kaynaklanan performans sorunlarını gidermek için basit ama oldukça etkili bir püf noktası sunuyor. Uygulamalarınızın akıcılığını ve kullanıcı memnuniyetini artırmak için hemen bu teknikleri keşfedin!
Modern mobil uygulamaların kullanıcılar tarafından hızlı ve sorunsuz bir deneyim sunması beklenir. Ancak React Native ile geliştirilen uygulamalarda zaman zaman performans sorunları yaşanabilir. Bu sorunlar genellikle ekranlar arası geçişlerde takılmalar, listelerde gezinirken akıcılık kaybı veya belirli işlemler sırasında uygulamanın donması şeklinde kendini gösterir. Kullanıcıların sabrı oldukça sınırlıdır; yavaş bir uygulama, doğrudan olumsuz bir kullanıcı deneyimi (UX) anlamına gelir ve uygulamanın terk edilme oranını artırabilir.
Peki, bu yavaşlamaların arkasındaki temel nedenler nelerdir? Çoğu zaman problem, JavaScript çalışma zamanı (runtime) ile Native UI arasında köprü kuran React Native mimarisinin inceliklerinden kaynaklanır. En yaygın performans darboğazlarını şu başlıklar altında sıralayabiliriz:
- Gereksiz Yeniden Oluşturmalar (Re-renders): Bir React bileşeni, props’ları veya state’i değiştiğinde yeniden render edilir. Ancak bazen, aslında görsel olarak veya mantıksal olarak değişmesi gerekmeyen bileşenler de gereksiz yere tekrar tekrar render edilir. Bu durum, özellikle karmaşık UI hiyerarşilerinde veya sık güncellenen verilerle çalışırken önemli bir performans düşüşüne yol açabilir.
- Büyük Veri Setleri ve Listeler: Binlerce öğe içeren bir listeyi doğrudan render etmek, uygulamanın bellek tüketimini artırır ve CPU’yu yorar. Her öğenin render edilmesi, özellikle düşük performanslı cihazlarda uygulamanın donmasına neden olabilir.
- Ağ İstekleri ve Veri İşleme: Asenkron ağ istekleri, büyük JSON verilerinin ayrıştırılması veya karmaşık veri transformasyonları ana JavaScript thread’ini bloke ederek UI’ın donmasına yol açabilir.
- Yoğun Animasyonlar ve Etkileşimler: Özellikle yoğun grafik hesaplamaları gerektiren veya birçok bileşeni aynı anda etkileyen animasyonlar, JavaScript ve UI thread’leri arasında sürekli senkronizasyon gerektirdiğinden performansı olumsuz etkileyebilir.
- Yanlış State Yönetimi: Global state yönetim kütüphaneleri (Redux, Context API vb.) yanlış kullanıldığında, tek bir küçük değişiklik dahi uygulamanın birçok farklı yerinde gereksiz render’ları tetikleyebilir.
Bu sorunlar genellikle gözle görülebilir bir yavaşlamaya neden olurken, bazen de uygulamanın pil ömrünü kısaltarak veya cihazın ısınmasına yol açarak dolaylı yollardan kendini belli eder. Bu makalede odaklanacağımız “basit ama etkili çözüm”, özellikle “Gereksiz Yeniden Oluşturmalar” sorununa karşı adeta bir kalkan görevi görecektir. Şimdi gelin, bu gizli düşmanı daha yakından inceleyelim.
Gereksiz Yeniden Oluşturmalar (Re-renders): React Native Performansının Gizli Düşmanı Nasıl Ortaya Çıkar ve Nasıl Engellenir?
React’in temel çalışma prensiplerinden biri, kullanıcı arayüzünü (UI) verilerdeki değişikliklere göre otomatik olarak güncellemesidir. Bir bileşenin state’i veya props’ları değiştiğinde, React bu bileşeni ve genellikle tüm alt bileşenlerini (child components) yeniden render eder. Bu mekanizma, React’i son derece reaktif ve geliştirici dostu yapar; ancak aynı zamanda performans sorunlarının da ana kaynağı olabilir, zira her render işlemi bir miktar hesaplama gücü gerektirir. Eğer bir bileşen, aslında hiçbir verisi değişmemesine rağmen tekrar tekrar render ediliyorsa, bu durum “gereksiz yeniden oluşturma” olarak adlandırılır.
Bu gereksiz re-render’lar çeşitli senaryolarda ortaya çıkabilir. Örneğin, bir üst bileşen (parent component) state’ini güncellediğinde, bu bileşen yeniden render edilir. React varsayılan olarak, parent bileşen render edildiğinde tüm çocuk bileşenlerini de yeniden render eder. Eğer bu çocuk bileşenlerin props’ları değişmediyse bile, yine de bu yeniden oluşturma işlemi gerçekleşir. Bu, özellikle derin ve karmaşık bileşen ağaçlarında, performans üzerinde domino etkisi yaratabilir. Örneğin, bir ana ekrandaki küçük bir sayacın güncellenmesi, aslında değişmeyen bir menü bileşenini, ürün listesini ve diğer UI öğelerini de yeniden render etmeye zorlayabilir. Bu tür senaryolar, performansı düşüren CPU döngülerinin israfına yol açar.
Bununla birlikte, fonksiyonel bileşenlerde sıklıkla karşılaşılan bir başka problem de props olarak geçirilen fonksiyon referanslarının her render’da yeniden oluşturulmasıdır. JavaScript’te, bir fonksiyon her tanımlandığında yeni bir bellek referansı alır. Eğer bir üst bileşen her render edildiğinde yeni bir fonksiyon tanımlanıp alt bileşenine prop olarak geçirilirse, alt bileşen için bu fonksiyonun “yeni bir prop” olduğu algılanır ve bileşen gereksiz yere yeniden render edilir. Bu durum, özellikle bir üst bileşenden alt bileşenlere tıklama veya veri gönderme gibi olay işleyicileri (event handlers) geçerken performansı olumsuz etkileyebilir.
State yönetim kütüphaneleri de bu durumu tetikleyebilir. Örneğin, Context API veya Redux kullanılırken, eğer bir bağlamdaki (context) veya depodaki (store) çok küçük bir değer değişirse, bu bağlama abone olan veya store’dan veri çeken tüm bileşenler, değişen veriyi doğrudan kullanmasalar bile yeniden render edilebilir. Yanlış tasarlanmış selector’lar veya provider’lar bu tür zincirleme re-render’ları tetikleyebilir ve performansın katlanarak düşmesine neden olabilir. Bu tür senaryoları tespit etmek için React DevTools Profiler gibi araçlar kullanılabilir; ancak tespit edildikten sonra en etkili çözüm, genellikle React’in sağladığı memoization mekanizmalarını doğru bir şekilde kullanmaktır. İşte tam da bu noktada, “Sihirli Üçlü” devreye giriyor.
Sihirli Üçlü: React.memo, useMemo ve useCallback ile Performansı Artırmanın Sırları Nelerdir?
React Native uygulamalarınızdaki gereksiz yeniden oluşturmaları engellemenin ve dolayısıyla performansı artırmanın en basit ama en etkili yolu, React’in sunduğu memoization (ezberleme) mekanizmalarını kullanmaktır. Bu mekanizmalar, bileşenlerin veya değerlerin belirli koşullar altında yeniden hesaplanmasını veya yeniden render edilmesini engelleyerek CPU ve bellek kullanımını optimize eder. İşte bu “sihirli üçlü”: React.memo, useMemo ve useCallback.
React.memo: Fonksiyonel Bileşenleri Akıllandırmak
React.memo, fonksiyonel bileşenler için bir üst düzey bileşen (Higher-Order Component – HOC) olarak işlev görür. Temel amacı, bir bileşenin props’ları değişmediği sürece yeniden render edilmesini engellemektir. React, bu HOC ile sarılmış bir bileşeni render etmeden önce, önceki props’ları ile mevcut props’larını karşılaştırır. Eğer props’lar aynıysa, React önceki render edilmiş çıktıyı yeniden kullanır ve bileşeni render etme adımını atlar. Bu, özellikle karmaşık ve sıkça kullanılan, ancak props’ları nadiren değişen bileşenler için muazzam bir performans kazancı sağlar.
Class bileşenlerindeki shouldComponentUpdate metoduna benzer bir mantıkla çalışır, ancak fonksiyonel bileşenler için çok daha basit bir kullanım sunar. Varsayılan olarak, props’ların sığ bir karşılaştırmasını (shallow comparison) yapar. Eğer daha derinlemesine bir karşılaştırma yapmanız gerekiyorsa, React.memo‘nun ikinci argümanına özel bir karşılaştırma fonksiyonu (arePropsEqual) geçirebilirsiniz.
Ne zaman kullanılır?
- Bir bileşen sıkça render ediliyor ancak props’ları çoğu zaman aynı kalıyorsa.
- Bileşen içindeki render işlemi pahalı hesaplamalar içeriyorsa.
- Bileşenin bir üst bileşenin state veya props değişikliği nedeniyle gereksiz yere yeniden render edilmesini önlemek istediğinizde.
İşte basit bir örnek:
import React from 'react';
import { Text, View, StyleSheet } from 'react-native';
const ExpensiveListItem = ({ item, onClick }) => {
// Bu bileşen, item prop'u değişmediği sürece yeniden render edilmemeli
console.log(Rendering Item: ${item.id});
return (
{item.name}
{item.description}
);
};
const styles = StyleSheet.create({
itemContainer: { padding: 10, borderBottomWidth: 1, borderColor: '#eee' },
itemText: { fontSize: 16, fontWeight: 'bold' },
itemDetail: { fontSize: 14, color: '#666' },
});
// React.memo ile sarmalayarak performansı optimize ediyoruz
export default React.memo(ExpensiveListItem);
Yukarıdaki örnekte, ExpensiveListItem bileşeni React.memo ile sarmalanmıştır. Artık bu bileşen, yalnızca item veya onClick props'larından biri değiştiğinde yeniden render edilecektir. Bu, büyük listelerde her bir öğe için gereksiz render'ları önleyerek büyük bir performans kazancı sağlayabilir.
useMemo: Pahalı Hesaplamaları ve Değerleri Ezberlemek
useMemo hook'u, pahalı veya yoğun hesaplamaları bir bileşenin her render edilişinde tekrar yapmasını engellemek için kullanılır. Belirli bir değerin (sayı, dizi, obje vb.) yalnızca bağımlılıkları değiştiğinde yeniden hesaplanmasını sağlar. Bu, özellikle büyük veri setleri üzerinde filtreleme, sıralama veya dönüştürme gibi işlemler yaparken çok faydalıdır.
import React, { useState, useMemo } from 'react';
import { View, Text, Button } from 'react-native';
const ProductList = ({ products, filterText }) => {
const [count, setCount] = useState(0);
// useMemo, products veya filterText değiştiğinde filtreleme işlemini tekrar yapar
// Aksi takdirde, component her render edildiğinde bu pahalı işlem tekrarlanmaz
const filteredProducts = useMemo(() => {
console.log('Filtreleme işlemi yapılıyor...');
return products.filter(product =>
product.name.toLowerCase().includes(filterText.toLowerCase())
);
}, [products, filterText]); // Bağımlılık dizisi
return (
Filtrelenmiş Ürün Sayısı: {filteredProducts.length}
Sayaç: {count}
);
};
Bu örnekte, filteredProducts değişkeni yalnızca products dizisi veya filterText değiştiğinde yeniden hesaplanacaktır. Eğer sadece count state'i değişirse (yani Sayacı Artır butonuna basılırsa), filteredProducts önceki değerini koruyacak ve filtreleme işlemi gereksiz yere tekrar çalışmayacaktır.
useCallback: Fonksiyon Referanslarını Sabitlemek
useCallback hook'u, useMemo'ya benzer ancak bir değeri ezberlemek yerine bir fonksiyonu ezberler. Bir fonksiyonel bileşenin her render edilişinde yeni bir fonksiyon referansı oluşturmasını engeller. Bu, özellikle alt bileşenlere prop olarak geçirilen olay işleyici (event handler) fonksiyonları için kritik öneme sahiptir. Eğer bir fonksiyon useCallback ile sarılmazsa ve bir alt bileşene prop olarak geçirilirse, o alt bileşen React.memo ile optimize edilmiş olsa bile, üst bileşen her render edildiğinde yeni bir fonksiyon referansı aldığı için yeniden render edilir.
import React, { useState, useCallback } from 'react';
import { View, Text, Button } from 'react-native';
import MyMemoizedButton from './MyMemoizedButton'; // React.memo ile sarılmış bir button
const ParentComponent = () => {
const [count, setCount] = useState(0);
// handleClick fonksiyonu, sadece count değiştiğinde yeniden oluşturulur
const handleClick = useCallback(() => {
setCount(prevCount => prevCount + 1);
}, []); // Boş bağımlılık dizisi, fonksiyonun sadece bir kez oluşturulmasını sağlar
return (
Sayaç: {count}
{/* MyMemoizedButton, handleClick fonksiyonu değişmediği sürece yeniden render edilmez */}
);
};
// MyMemoizedButton.js içeriği
/*
// import React from 'react';
// import { Button } from 'react-native';
// const MyButton = ({ title, onPress }) => {
// console.log(Rendering ${title} Button);
// return ;
// };
// export default React.memo(MyButton);
*/
Yukarıdaki örnekte, handleClick fonksiyonu useCallback ile sarılmıştır. Bağımlılık dizisi boş olduğu için ([]), bu fonksiyon sadece bir kez, bileşenin ilk render edilişinde oluşturulur. Bu sayede, MyMemoizedButton bileşeni, ParentComponent her render edildiğinde gereksiz yere yeniden render edilmez, çünkü onPress prop'u olarak aldığı fonksiyonun referansı değişmez. Bu üçlünün doğru kullanımıyla, uygulamanızın performansında gözle görülür bir artış sağlamak mümkündür.
Gerçek Dünya Senaryosu: E-ticaret Uygulaması Ürün Listesi Performansını İyileştirme Vaka Analizi
Haydi, gerçek bir senaryo üzerinden "Sihirli Üçlü"nün nasıl bir fark yaratabileceğini inceleyelim. Bir e-ticaret uygulamasında, kullanıcıların binlerce ürün arasında gezindiği, arama yaptığı, filtreler uyguladığı ve ürün detaylarını görüntülediği karmaşık bir "Ürün Listesi" ekranımız olduğunu varsayalım. Uygulamanın geliştiricileri, ürün listesi ekranında kaydırma yaparken takılmalar, filtreleme uygulandığında uzun gecikmeler ve genel olarak akıcılık eksikliği raporları alıyorlar.
Problem Tespiti:
React DevTools Profiler kullanılarak yapılan bir analizde, uygulamanın ana ProductListScreen bileşeninin her kaydırma olayında veya filtre değiştirildiğinde gereksiz yere tüm alt bileşenlerini (özellikle her bir ProductCard bileşenini) yeniden render ettiği gözlemleniyor. Ayrıca, filtreleme mantığı her klavye tuşuna basıldığında yeniden çalışıyor ve bu da ana JavaScript thread'ini bloke ediyor. Bu durum, özellikle yüzlerce ürünün bulunduğu durumlarda belirgin bir yavaşlığa yol açuyor.
Uygulanan Çözüm: "Sihirli Üçlü" ile Optimizasyon
Geliştirme ekibi, bu performans darboğazlarını gidermek için aşağıdaki adımları izledi:
ProductCardBileşeninin Optimizasyonu (React.memo): Her bir ürün kartı, uygulamanın en sık tekrar eden ve görsel olarak karmaşık bileşenlerinden biridir. Bu bileşen, sadece kendiproductprop'u değiştiğinde yeniden render edilmelidir.// components/ProductCard.js import React from 'react'; import { View, Text, Image, StyleSheet, TouchableOpacity } from 'react-native'; const ProductCard = ({ product, onAddToCart, onNavigateToDetail }) => { console.log(Rendering ProductCard: ${product.name}); return (onNavigateToDetail(product.id)} style={styles.card}> ); }; const styles = StyleSheet.create({ // ... stil tanımları }); export default React.memo(ProductCard); // Sadece prop'lar değişince render et!{product.name} ${product.price.toFixed(2)} onAddToCart(product.id)} style={styles.addButton}> Sepete Ekle Bu değişiklikle,
FlatListiçinde yüzlerceProductCardolsa bile, yalnızca görünür alana giren veya güncellenen kartlar yeniden render ediliyor. Diğer kartlar, props'ları değişmediği sürece performans maliyeti yaratmıyor.- Filtreleme Mantığının Optimizasyonu (
useMemo): Ürün listesini filtreleme işlemi, kullanıcı bir arama terimi girdiğinde her tuş vuruşunda çalışıyordu. Bu, gereksiz ve pahalı bir işlemdi.// screens/ProductListScreen.js'de import React, { useState, useMemo, useCallback } from 'react-native'; // ... diğer importlar const ProductListScreen = ({ productsData }) => { const [searchText, setSearchText] = useState(''); const [categoryFilter, setCategoryFilter] = useState('all'); const filteredProducts = useMemo(() => { console.log('Ürün listesi filtreleniyor...'); return productsData.filter(product => { const matchesSearch = product.name.toLowerCase().includes(searchText.toLowerCase()); const matchesCategory = categoryFilter === 'all' || product.category === categoryFilter; return matchesSearch && matchesCategory; }); }, [productsData, searchText, categoryFilter]); // Sadece bu bağımlılıklar değişince yeniden filtrele // ... diğer UI ve state yönetimi };useMemosayesinde,filteredProductsdizisi sadeceproductsData,searchTextveyacategoryFilterdeğiştiğinde yeniden hesaplanıyor. KullanıcısearchTextgirerken her tuş vuruşunda diğer state'ler değişmediği sürece filtreleme mantığı tekrarlanmıyor, bu da UI'ın daha tepkisel olmasını sağlıyor. - Olay İşleyicilerinin Optimizasyonu (
useCallback):ProductCardbileşenineonAddToCartveonNavigateToDetailgibi fonksiyonlar prop olarak geçiliyordu. Üst bileşen (ProductListScreen) her render olduğunda bu fonksiyonlar yeniden oluşturulduğu için,React.memoile optimize edilmişProductCardbileşenleri bile gereksiz yere render ediliyordu.// screens/ProductListScreen.js'de devam // ... const handleAddToCart = useCallback((productId) => { console.log(Ürün ${productId} sepete eklendi.); // Sepete ekleme mantığı }, []); // Bu fonksiyonun referansı hiç değişmez const handleNavigateToDetail = useCallback((productId) => { console.log(Ürün ${productId} detayına gidiliyor.); // Navigasyon mantığı }, []); // Bu fonksiyonun referansı hiç değişmez // ... render fonksiyonunda FlatList içindeki ProductCard kullanımı: //item.id.toString()} // renderItem={({ item }) => ( // // )} // /> useCallbackile bu fonksiyonların referansları sabit tutuldu. ArtıkProductListScreenrender olduğunda bilehandleAddToCartvehandleNavigateToDetailfonksiyonları yeniden oluşturulmuyor, bu daProductCardbileşenlerininReact.memooptimizasyonundan tam olarak faydalanmasını sağlıyor.
Sonuçlar ve Kazanımlar:
Bu basit ama stratejik optimizasyonlar sonucunda, e-ticaret uygulamasının ürün listesi ekranında kaydırma akıcılığı önemli ölçüde arttı. Filtreleme ve arama işlemleri anında tepki vermeye başladı ve genel kullanıcı deneyimi gözle görülür şekilde iyileşti. Profiler araçları, render sürelerinde %60'a varan azalma ve JavaScript thread'indeki yüklenmede belirgin düşüşler gösterdi. Kullanıcı memnuniyeti arttı ve uygulama terk oranları azaldı. Bu vaka analizi, "Sihirli Üçlü"nün React Native performans optimizasyonunda ne kadar güçlü bir araç olduğunu açıkça ortaya koymaktadır.
İleri Düzey Optimizasyon İpuçları ve En İyi Uygulamalar: Daha Akıcı Deneyimler İçin
Yukarıdaki "Sihirli Üçlü" teknikleri, React Native uygulamalarınızdaki performans sorunlarının büyük bir kısmını çözmenize yardımcı olacaktır. Ancak, en üst düzey performansı hedefliyorsanız veya daha karmaşık senaryolarla karşılaşıyorsanız, uygulayabileceğiniz bazı ileri düzey optimizasyon ipuçları ve en iyi uygulamalar bulunmaktadır.
- Sanallaştırılmış Listeler Kullanın (
FlatList,SectionList):Büyük veri setleri içeren listeleri render ederken
ScrollViewyerine mutlakaFlatListveyaSectionListkullanın. Bu bileşenler, yalnızca ekranda görünen öğeleri render ederek "sanallaştırma" (virtualization) adı verilen bir teknikle bellek ve CPU kullanımını dramatik şekilde düşürür. Bu, özellikle binlerce öğe içeren listelerde fark yaratır.import React from 'react'; import { FlatList, View, Text } from 'react-native'; const data = Array.from({ length: 1000 }, (_, i) => ({ id: i.toString(), title:Öğe ${i}})); const MyVirtualizedList = () => (item.id} renderItem={({ item }) => {item.title} } initialNumToRender={10} // Başlangıçta kaç öğe render edilsin maxToRenderPerBatch={5} // Her batch'te kaç öğe eklensin windowSize={21} // Viewport'un kaç katı öğe render edilsin (varsayılan 21) /> ); - React DevTools Profiler ve Flipper ile Derinlemesine Analiz:
Performans sorunlarının kök nedenini bulmak için sezgisel tahminler yapmak yerine, araçları kullanın. React DevTools Profiler, hangi bileşenlerin ne sıklıkla ve ne kadar süreyle render edildiğini görselleştirmenizi sağlar. Flipper, React Native için geliştirilmiş kapsamlı bir hata ayıklama aracıdır ve ağ isteklerinden yerel performans metriklerine kadar birçok alanda size yardımcı olabilir. Bu araçları düzenli olarak kullanarak darboğazları doğru bir şekilde tespit edebilir ve optimizasyon çabalarınızı en verimli alanlara yönlendirebilirsiniz.
- Gereksiz Bağımlılıkları Azaltın ve Doğru Yönetin:
useMemoveuseCallbackkullanırken bağımlılık dizisini (dependency array) doğru doldurmak kritik öneme sahiptir. Boş bir dizi ([]) sadece ilk render'da çalışmasını sağlarken, çok fazla bağımlılık, memoization'ın faydasını azaltabilir. Ayrıca, gereksiz bağımlılıklar eklemek, beklediğiniz optimizasyonun gerçekleşmemesine neden olabilir. Örneğin, bir fonksiyon içerisinde kullanılan ve aslında değişmeyen sabit bir değeri bağımlılık dizisine eklemek gereksizdir. - Bileşenleri Minimalize Edin ve Bölün:
Tek bir büyük ve karmaşık bileşen yerine, sorumlulukları ayrılmış daha küçük bileşenler oluşturun. Her bileşenin tek bir işi yapması (Single Responsibility Principle), hem kodun okunabilirliğini artırır hem de
React.memogibi optimizasyon tekniklerinin daha etkili uygulanmasını sağlar. Küçük bileşenler, daha az prop'a sahip olma eğilimindedir ve bu da memoization'ın daha sık başarılı olmasına yardımcı olur. - Yerel Modüller (Native Modules) ve JSI Kullanımı:
Eğer çok yoğun ve performans kritik bir işlem (örneğin, karmaşık görüntü işleme, yoğun matematiksel hesaplamalar) JavaScript tarafında yavaş kalıyorsa, bu işlemi Java/Kotlin (Android) veya Objective-C/Swift (iOS) dillerinde yazılmış yerel bir modüle taşıyabilirsiniz. React Native'in Yeni Mimarisi ile gelen JSI (JavaScript Interface) ise, JavaScript ve Native kod arasında köprüden geçiş ihtiyacını ortadan kaldırarak çok daha hızlı ve senkronize bir iletişim sağlar. Bu yöntemler, en uç performans optimizasyonları için geçerlidir.
- Görsel Geri Bildirim ve İskelet Ekranlar:
Bazı yavaşlamalar kaçınılmaz olabilir (örneğin, uzun süren ağ istekleri). Bu durumlarda, kullanıcıya bekleme süresini daha katlanılabilir hale getirmek için iskelet ekranlar (skeleton screens), yükleme göstergeleri veya animasyonlu yükleme durumları sunun. Bu, algılanan performansı artırır ve kullanıcının uygulamanın donduğunu düşünmesini engeller.
Sonuç: React Native Uygulamalarınızın Performansını Kalıcı Olarak Artırmak Mümkün!
React Native, harika bir mobil uygulama geliştirme çerçevesi olsa da, performans konusunda dikkatli olunmadığında yavaş ve tepkisiz uygulamalarla karşılaşmak kaçınılmazdır. Ancak bu makalede ele aldığımız "Sihirli Üçlü" olarak adlandırdığımız React.memo, useMemo ve useCallback gibi temel optimizasyon teknikleriyle, bu sorunların üstesinden gelmek ve uygulamanızın akıcılığını önemli ölçüde artırmak mümkündür.
Özellikle gereksiz yeniden oluşturmalar, React tabanlı uygulamalardaki en yaygın performans sorunlarından biridir. Bu teknikler sayesinde, bileşenlerinizin yalnızca gerçekten ihtiyaç duyduklarında güncellenmesini sağlayarak CPU döngülerinden tasarruf eder, bellek kullanımını azaltır ve kullanıcılara çok daha akıcı bir deneyim sunarsınız. E-ticaret uygulaması vaka analizimizde de gördüğümüz gibi, bu basit ama etkili yaklaşımlar, gerçek dünya senaryolarında somut performans iyileştirmeleri sağlayabilir.
Unutmamak gerekir ki, performans optimizasyonu sürekli bir süreçtir. Uygulamanız büyüdükçe ve yeni özellikler eklendikçe, yeni darboğazlar ortaya çıkabilir. Bu nedenle, React DevTools Profiler ve Flipper gibi araçları kullanarak uygulamanızın performansını düzenli olarak izlemeniz ve karşılaştığınız sorunlara karşı proaktif çözümler geliştirmeniz önemlidir. Başarıya giden yol, sürekli öğrenme ve uygulamadan geçer.
Şimdi öğrendiğiniz bu bilgileri kendi React Native projelerinizde uygulamaya başlayın ve kullanıcılarınızın keyif aldığı hızlı ve sorunsuz bir mobil deneyim yaratın. Uygulamanızın performansını kalıcı olarak artırmak, artık sizin elinizde!
Sıkça Sorulan Sorular (SSS)
React.memokullanmak her zaman iyi bir fikir midir?- Hayır, her zaman değil.
React.memo, props'ların sığ bir karşılaştırmasını yapar. Bu karşılaştırma işleminin kendisi de bir maliyete sahiptir. Eğer bir bileşenin props'ları çok sık değişiyorsa veya bileşenin kendi render maliyeti çok düşükse,React.memokullanmak gereksiz bir ek yük oluşturabilir ve hatta performansı hafifçe düşürebilir. Sadece pahalı veya sıkça render edilen ancak props'ları nadiren değişen bileşenler için kullanılması önerilir. useMemoveuseCallbackarasındaki fark nedir?useMemobir değeri (bir sayı, obje, dizi, vb.) ezberlerken,useCallbackbir fonksiyonu ezberler. Her ikisi de bağımlılık dizileri (dependency array) değişmediği sürece önceki değeri/fonksiyon referansını döndürür.useMemopahalı hesaplamaların sonucunu önbelleğe almak için,useCallbackise alt bileşenlere prop olarak geçilen fonksiyonların referansını sabit tutarak gereksiz yeniden render'ları önlemek için kullanılır.FlatListkullanırken bile takılmalar yaşıyorsam ne yapmalıyım?FlatList'in performansı, içindeki öğelerin (renderItem) ne kadar iyi optimize edildiğine bağlıdır. ÖğeleriReact.memoile sarmalamak ilk adımdır. AyrıcaFlatList'ingetItemLayout,initialNumToRender,maxToRenderPerBatchvewindowSizegibi optimizasyon prop'larını doğru ayarladığınızdan emin olun. Görsel olarak karmaşık öğelerden kaçının ve heavy hesaplamaları öğenin dışına taşıyın. Debug modunda çalışmak da performansı etkileyebilir, release modda test edin.- Tüm state ve prop'ları
useMemo/useCallbackile sarmalamalı mıyım? - Hayır, bu kötü bir pratik olur. Her
useMemoveyauseCallbackçağrısı, React'in bağımlılıkları takip etmesi ve karşılaştırması için ek bir maliyet getirir. Bu hook'ları sadece pahalı hesaplamalar, büyük veri yapıları veya alt bileşenlere prop olarak geçirilen fonksiyonlar gibi performans darboğazı olabilecek durumlarda kullanmalısınız. Aşırı kullanım, kodunuzu karmaşıklaştırır ve beklenen performans kazancını sağlamayabilir. - React Native'deki "Bridge" performans sorunlarına neden olabilir mi?
- Evet, "Bridge" (köprü), JavaScript thread'i ile Native UI thread'i arasındaki iletişimi sağlayan önemli bir bileşendir. Çok sık ve büyük veri transferleri, köprüyü tıkayarak performans sorunlarına yol açabilir. Özellikle animasyonlar ve çok sayıda UI güncellemesi içeren senaryolarda bu durum gözlemlenebilir. Yeni Mimari'deki JSI (JavaScript Interface) bu köprü bağımlılığını azaltmayı ve daha doğrudan iletişimi sağlamayı hedefleyerek performansı artırmaktadır. Eğer köprü darboğazı yaşıyorsanız, Native Modüller veya JSI gibi daha gelişmiş çözümleri araştırmanız gerekebilir.