React Compiler ile Karmaşıklığa Son: useMemo ve useCallback Olmadan Otomatik Performans
React Compiler ile Karmaşıklığa Son: useMemo ve useCallback Olmadan Otomatik Performans
React ekosisteminde yıllardır süregelen en büyük tartışmalardan ve geliştiriciyi en çok yoran konulardan biri hiç şüphesiz manuel performans optimizasyonuydu. Bir bileşenin ne zaman ve neden yeniden render edildiğini (re-render) takip etmek, eksik yazılan bağımlılık dizileriyle (dependency arrays) boğuşmak ve her yere bilinçsizce useMemo veya useCallback serpiştirmek çoğumuzun günlük rutininin bir parçası haline gelmişti.
Ancak React ekibinin duyurduğu React Compiler (eski adıyla React Forget) ile bu devir kapanıyor. Derleme aşamasında (build-time) çalışan bu yeni derleyici sayesinde, performans optimizasyonları artık yazılımcının sırtındaki bir yük olmaktan çıkıp tamamen otomatik bir süreç haline geliyor.
Bu yazıda, React Compiler'ın mantığını, useMemo ve useCallback ihtiyacını nasıl ortadan kaldırdığını ve kod kalitemizi nasıl dönüştüreceğini detaylarıyla inceleyeceğiz.
1. Geçmişin Çilesi: Neden Manuel Memoization Yapıyorduk?
React varsayılan olarak bir bileşenin durumu (state) değiştiğinde, o bileşeni ve onun altındaki tüm alt bileşenleri (child components) yeniden render eder. Büyük ölçekli uygulamalarda bu durum ciddi performans kayıplarına yol açabiliyordu.
Bu sorunu çözmek için React bize üç temel araç sunmuştu:
1. React.memo: Bileşenin prop'ları değişmediği sürece re-render olmasını engeller.
2. useMemo: Pahalı hesaplamaların sonuçlarını hafızada tutar (cache).
3. useCallback: Fonksiyon referanslarının her render'da yeniden oluşturulmasını engeller.
Manuel Optimizasyonun Yan Etkileri:
- Kod Kirliliği (Boilerplate): Basit bir bileşen bile okunması zor Hook zincirleriyle dolabiliyordu.
- İnsan Hatası: Bağımlılık dizisine bir değişken yazmayı unutmak, zor tespit edilen "stale closure" veya sonsuz döngü (infinite loop) hatalarına neden oluyordu.
- Gereksiz Karmaşıklık: Hangi fonksiyonun veya değerin gerçekten memoize edilmesi gerektiğine karar vermek zihinsel bir yük (mental overhead) oluşturuyordu.
2. React Compiler Nedir ve Nasıl Çalışır?
React Compiler, uygulamanızı derleme (build) aşamasında analiz eden ve JavaScript kuralları ile React mantığını birleştirerek kodu otomatik olarak optimizasyona tabi tutan bir Babel/SWC eklentisidir.
Geleneksel React mimarisinde memoization işlemi çalışma zamanında (runtime) geliştirici tarafından yönetilirken; React Compiler bu süreci derleme zamanında (compile-time) kendi üstlenir.
Sihrin Arkasındaki Mantık: Otomatik Memoization
Derleyici, kodunuzdaki veri akışını ve bağımlılıkları analiz eder. Bir değerin veya fonksiyonun yeniden hesaplanmasına gerçekten gerek olup olmadığını anlar ve arkaplanda kodu otomatik olarak bellek optimizasyonlu (memoized) hale getirir.
3. Kod Karşılaştırması: Öncesi ve Sonrası
React Compiler'ın gücünü anlamanın en iyi yolu kod örneklerine bakmaktır.
React Compiler Öncesi (Geleneksel Yöntem)
Aşağıdaki basit örnekte, bileşenin her render oluşunda pahalı bir hesaplamanın tekrar çalışmasını önlemek ve alt bileşene sabit bir fonksiyon referansı geçmek için useMemo ve useCallback kullanmak zorundaydık:
import React, { useState, useMemo, useCallback } from 'react';
function ProductList({ products, filterText }) {
const [selectedId, setSelectedId] = useState(null);
// Pahalı filtreleme işlemini önbelleğe alıyoruz
const filteredProducts = useMemo(() => {
return products.filter(p => p.name.includes(filterText));
}, [products, filterText]);
// Fonksiyon referansını koruyoruz
const handleSelect = useCallback((id) => {
setSelectedId(id);
}, []);
return (
<div>
<SearchSummary count={filteredProducts.length} />
{filteredProducts.map(product => (
<ProductCard
key={product.id}
product={product}
onSelect={handleSelect}
/>
))}
</div>
);
}
React Compiler Sonrası (Yeni Yaklaşım)
React Compiler aktif olduğunda, yukarıdaki karmaşık kod yerine sadece standart, temiz JavaScript yazarsınız. Hook'lara veya bağımlılık dizilerine ihtiyacınız kalmaz:
import { useState } from 'react';
function ProductList({ products, filterText }) {
const [selectedId, setSelectedId] = useState(null);
// Derleyici bu filtrelemenin ne zaman yenilenmesi gerektiğini otomatik anlar!
const filteredProducts = products.filter(p => p.name.includes(filterText));
// Derleyici bu fonksiyonun referansını otomatik yönetir!
const handleSelect = (id) => {
setSelectedId(id);
};
return (
<div>
<SearchSummary count={filteredProducts.length} />
{filteredProducts.map(product => (
<ProductCard
key={product.id}
product={product}
onSelect={handleSelect}
/>
))}
</div>
);
}
Sonuç: Yazdığınız kod çok daha kısa, okunabilir ve bakımı kolaydır. Arka planda derleyici, birinci örnekteki gibi (ve hatta daha optimize) bir çıktı üretir.
4. Geliştiriciler İçin Ne Değişiyor?
React Compiler'ın hayatımıza girmesiyle birlikte yazılım geliştirme süreçlerimizde büyük bir zihniyet değişimi yaşanıyor:
- Sadece İş Mantığına (Business Logic) Odaklanmak: Artık "Buraya useCallback koysam mı?", "Bağımlılık dizisi doğru mu?" diye düşünmek zorunda değilsiniz.
- Sıfır Bağımlılık Dizisi Hatası: Eksik veya yanlış yazılan dependency array yüzünden yaşanan bug'lar tamamen tarihe karışıyor.
- Daha Az Kod, Daha Yüksek Okunabilirlik: Dosyalarınızdaki boilerplate kod miktarı önemli ölçüde azalıyor.
- Varsayılan Olarak Hızlı Uygulamalar: Optimizasyon yapmayı unuttuğunuz için yavaşlayan sayfalar artık olmayacak. Tüm uygulamanız varsayılan olarak maksimum performansta çalışacak.
5. React Kuralları (Rules of React) Artık Daha Da Önemli!
React Compiler bir mucize gibi görünse de, düzgün çalışabilmesi için tek bir şartı var: React Kurallarına Kesinlikle Uymak.
Derleyici, kodunuzun öngörülebilir ve saf (pure) olduğunu varsayar. Eğer uygulamanızda aşağıdaki gibi "anti-pattern" durumlar varsa, derleyici bileşeni güvenle optimize edemeyebilir ve o bileşeni optimizasyon dışı bırakabilir (skip eder):
- State veya Prop'ları Doğrudan Mutasyona Uğratmak:
javascript // YANLIŞ! Mutasyon derleyicinin kafasını karıştırır. props.items.push(newItem); - Render Sırasında Yan Etkiler (Side Effects) Çalıştırmak:
Render fonksiyonları içinde DOM değiştirmek veya API çağrısı yapmak gibi işlemler yapılmamalı, bunlar
useEffectiçinde kalmalıdır. - Hook'ları Şartlı Yapılar (if/else) İçinde Çağırmak.
Neyse ki, React ekibi bu kurallara uyup uymadığınızı denetlemek için ESLint React Compiler Plugin'ini de kullanıma sundu. Bu eklenti, derleyicinin anlamasını zorlaştıracak kodları yazdığınız anda sizi uyarıyor.
Özet: React İçin Yeni Bir Çağ
React Compiler, React'ın gelişim yolculuğundaki en radikal ve heyecan verici adımlardan biridir. Geliştiricileri manuel hafıza yönetimi külfetinden kurtararak, UI geliştirmeyi tekrar eğlenceli ve yalın bir hale getiriyor.
useMemo ve useCallback Hook'ları bir gecede yok olmayacak; geriye dönük uyumluluk adına React içinde kalmaya devam edecekler. Ancak yeni nesil React projelerinde bu Hook'ları yazmak neredeyse hiç gerekmeyecek.
Geleceğe hazır olmak için yapmanız gereken tek şey: Kodlarınızı React kurallarına uygun yazmak ve arkasındaki harika derleyicinin performans işini sizin yerinize halletmesine izin vermek!