React Performans Optimizasyonu: Kapsamlı Rehber
İçindekiler
React uygulamalarının performansını optimize etmek, modern web geliştirmenin en kritik konularından biridir. Büyük ölçekli uygulamalarda performans optimizasyonu, kullanıcı deneyimini doğrudan etkileyen en önemli faktörlerden biridir. Bu kapsamlı rehberde, React'in render mekanizmalarından ileri düzey optimizasyon tekniklerine kadar her şeyi detaylıca ele alacağız.
1. React Render Döngüsünü Anlamak
React'in render mekanizmasını anlamak, performans optimizasyonunun temelidir. Bu bölümde, Virtual DOM'un nasıl çalıştığını, Reconciliation sürecini ve Fiber mimarisinin getirdiği yenilikleri detaylı olarak inceleyeceğiz.
1.1 Virtual DOM ve Reconciliation
Virtual DOM, React'in en önemli özelliklerinden biridir. Gerçek DOM manipülasyonlarını minimize ederek performansı artırır. Virtual DOM, gerçek DOM'un hafif bir kopyasıdır ve React, değişiklikleri önce bu kopya üzerinde uygular.
Virtual DOM'un Avantajları
- Batch Update: Birden fazla değişiklik tek seferde uygulanır
- Cross-browser Uyumluluk: DOM manipülasyonları tarayıcıdan bağımsız çalışır
- Performans: Gereksiz DOM güncellemeleri önlenir
// Virtual DOM örneği
const virtualElement = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Başlık'),
React.createElement('p', null, 'İçerik')
);
// JSX ile aynı yapı
const JSXElement = (
<div className="container">
<h1>Başlık</h1>
<p>İçerik</p>
</div>
);
Reconciliation süreci, Virtual DOM ile gerçek DOM arasındaki farkları bulur ve minimum sayıda DOM manipülasyonu ile güncellemeleri gerçekleştirir. Bu süreçte React, aşağıdaki stratejileri kullanır:
- Farklı Tip Elementler: Eski ağaç kaldırılır, yeni ağaç oluşturulur
- Aynı Tip DOM Elementleri: Sadece değişen özellikler güncellenir
- Aynı Tip Component Elementleri: Component instance korunur, props güncellenir
1.2 React Fiber Mimarisi
Fiber, React 16 ile birlikte gelen yeni reconciliation motorudur. Render işlemini küçük parçalara bölerek, tarayıcının ana thread'ini bloklamadan çalışmasını sağlar.
// Fiber prioritization örneği
const LowPriorityComponent = () => {
const [count, setCount] = useState(0);
// Düşük öncelikli güncelleme
const handleLowPriority = () => {
requestIdleCallback(() => {
setCount(prev => prev + 1);
});
};
// Yüksek öncelikli güncelleme
const handleHighPriority = () => {
setCount(prev => prev + 1);
};
return (
<div>
<button onClick={handleLowPriority}>Düşük Öncelik</button>
<button onClick={handleHighPriority}>Yüksek Öncelik</button>
</div>
);
};
Fiber İpuçları
Fiber mimarisinde render fazları interruptible'dır. Bu nedenle render metodları pure olmalı ve side effect içermemelidir.
1.3 Render Fazları
React'in render süreci iki ana fazdan oluşur: Render Fazı ve Commit Fazı. Render fazı interruptible iken, commit fazı atomic'tir.
2. Memoization Teknikleri
Memoization, pahalı hesaplamaların sonuçlarını önbelleğe alarak performansı artıran bir optimizasyon tekniğidir. React'te üç temel memoization tekniği bulunur: React.memo, useMemo ve useCallback.
2.1 React.memo Kullanımı
React.memo, bir component'in gereksiz yere yeniden render edilmesini önler. Props değişmedikçe component'in yeniden render edilmemesini sağlar.
// React.memo kullanım örneği
const ExpensiveComponent = React.memo(({ data, onItemClick }) => {
console.log('ExpensiveComponent rendered');
return (
<div>
{data.map(item => (
<Item
key={item.id}
{...item}
onClick={onItemClick}
/>
))}
</div>
);
}, (prevProps, nextProps) => {
// Custom comparison function
return (
prevProps.data.length === nextProps.data.length &&
prevProps.onItemClick === nextProps.onItemClick
);
});
2.2 useMemo Hook'u
useMemo, pahalı hesaplamaların sonuçlarını önbelleklememizi sağlar. Özellikle kompleks hesaplamalar ve büyük veri işlemleri için kullanışlıdır.
const ComplexComponent = ({ data }) => {
const processedData = useMemo(() => {
return data.filter(item => item.active)
.map(item => ({
...item,
price: calculatePrice(item)
}))
.sort((a, b) => b.price - a.price);
}, [data]);
return (
<ul>
{processedData.map(item => (
<li key={item.id}>{item.name}: {item.price}TL</li>
))}
</ul>
);
};
2.3 useCallback Hook'u
useCallback, fonksiyonları memoize eder. Özellikle child component'lere prop olarak geçilen fonksiyonlarda kullanışlıdır.
const ParentComponent = () => {
const [items, setItems] = useState([]);
const handleDelete = useCallback((id) => {
setItems(prev => prev.filter(item => item.id !== id));
}, []);
return (
<div>
{items.map(item => (
<ListItem
key={item.id}
item={item}
onDelete={handleDelete}
/>
))}
</div>
);
};
3. State Yönetimi ve Performans
Büyük React uygulamalarında state yönetimi, performansı etkileyen en önemli faktörlerden biridir. Doğru state yönetimi stratejisi, gereksiz render'ları önler ve uygulamanın daha hızlı çalışmasını sağlar.
3.1 Context API Optimizasyonu
// Optimized Context yapısı
const ThemeContext = React.createContext();
const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
// Value'yu memoize ediyoruz
const contextValue = useMemo(() => ({
theme,
setTheme
}), [theme]);
return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
};
3.2 Redux Performance Tips
Redux kullanırken performansı artırmak için dikkat edilmesi gereken noktalar:
- Normalizasyon: İç içe veri yapılarından kaçının
- Seçici Memoization: createSelector kullanın
- Action Batch: Multiple dispatch'leri birleştirin
// Redux Toolkit ile performans optimizasyonu
import { createSelector } from '@reduxjs/toolkit';
const selectUsers = state => state.users;
const selectActiveFilter = state => state.filters.active;
const selectActiveUsers = createSelector(
[selectUsers, selectActiveFilter],
(users, activeFilter) => users.filter(user => user.active === activeFilter)
);
3.3 Zustand ve Recoil
Modern state yönetim kütüphaneleri, performans odaklı çözümler sunar:
// Zustand örneği
import create from 'zustand';
const useStore = create((set) => ({
tasks: [],
addTask: (task) => set((state) => ({
tasks: [...state.tasks, task]
})),
removeTask: (id) => set((state) => ({
tasks: state.tasks.filter(task => task.id !== id)
}))
}));
4. Code-Splitting ve Lazy Loading
Büyük uygulamaları daha küçük parçalara bölerek yükleme süresini optimize etmek çok önemlidir.
4. Dynamic Imports
const MyComponent = () => {
const [Chart, setChart] = useState(null);
const loadChart = async () => {
const module = await import('react-chartjs-2');
setChart(() => module.Line);
};
return (
<div>
<button onClick={loadChart}>Grafik Yükle</button>
{Chart && <Chart data={chartData} />}
</div>
);
};
4.2 Route-based Splitting
Route bazlı code splitting, uygulamanızın farklı sayfalarını ayrı chunk'lar halinde yüklemenizi sağlar.
// React Router ile route bazlı code splitting
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { Suspense, lazy } from 'react';
// Lazy loaded routes
const Dashboard = lazy(() => import('./routes/Dashboard'));
const Profile = lazy(() => import('./routes/Profile'));
const Settings = lazy(() => import('./routes/Settings'));
function App() {
return (
<BrowserRouter>
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
4.3 Component-based Splitting
Büyük component'leri ihtiyaç anında yükleyerek başlangıç yükleme süresini azaltabilirsiniz.
// Component bazlı code splitting örneği
const VideoPlayer = lazy(() => import('./components/VideoPlayer'));
const Comments = lazy(() => import('./components/Comments'));
function BlogPost({ hasVideo }) {
return (
<article>
<h1>Blog Başlığı</h1>
<p>İçerik...</p>
{hasVideo && (
<Suspense fallback={<VideoPlaceholder />}>
<VideoPlayer />
</Suspense>
)}
<Suspense fallback={<CommentsSkeleton />}>
<Comments />
</Suspense>
</article>
);
};
5. React Server Components
React Server Components (RSC), React 18 ile birlikte gelen ve serverside rendering'i yeni bir seviyeye taşıyan özellikdir. RSC, client bundle size'ı küçültür ve initial page load performansını artırır.
5.1 RSC Fundamentals
React Server Components (RSC), sunucu tarafında render edilen ve istemciye sıkıştırılmış bir format olarak gönderilen özel React bileşenleridir.
'use server';
// Server Component örneği
async function UserProfile({ userId }) {
const user = await db.user.findById(userId);
const permissions = await getPermissions(userId);
return (
<div>
<h2>{user.name}</h2>
<ClientComponent permissions={permissions} />
</div>
);
}
5.2 Streaming SSR
Streaming SSR, sayfa içeriğini parça parça göndermeyi sağlayarak Time to First Byte (TTFB) süresini azaltır.
// Next.js 13+ ile Streaming SSR örneği
import { Suspense } from 'react';
async function SlowComponent() {
const data = await fetch('api/slow-data');
return <div>{data}</div>;
}
export default function Page() {
return (
<div>
<h1>Anında Görünen Başlık</h1>
<Suspense fallback={<Loading />}>
<SlowComponent />
</Suspense>
</div>
);
}
5.3 Hybrid Rendering Patterns
Hybrid rendering, statik ve dinamik içeriği birleştirerek optimal performans sağlar.
// Hybrid rendering örneği
'use client';
// Statik içerik (build time'da oluşturulur)
export async function generateStaticParams() {
const products = await getProducts();
return products.map((product) => ({
id: product.id,
}));
}
// Dinamik içerik (runtime'da güncellenir)
export default function ProductPage({ params }) {
const { id } = params;
const [inventory, setInventory] = useState(null);
useEffect(() => {
// Canlı stok bilgisi
const subscription = subscribeToInventory(id, setInventory);
return () => subscription.unsubscribe();
}, [id]);
return (
<div>
<StaticProductDetails id={id} />
<LiveInventoryStatus inventory={inventory} />
</div>
);
}
RSC Best Practices
- Veri getirme işlemlerini server component'lerde yapın
- İnteraktif UI elementlerini client component'lerde tutun
- Streaming için Suspense boundary'leri kullanın
- Edge Runtime kullanarak latency'yi azaltın
Özet ve İleri Okuma
React performans optimizasyonu, birçok farklı teknik ve yaklaşımın bir kombinasyonudur. Bu rehberde ele aldığımız temel noktalar:
- Virtual DOM ve Reconciliation mekanizmaları
- Memoization teknikleri (React.memo, useMemo, useCallback)
- State yönetimi optimizasyonları
- Code splitting ve lazy loading stratejileri
- Server Components ve modern rendering yaklaşımları
Temel Prensipler
- Erken optimizasyondan kaçının - önce ölçün, sonra optimize edin
- React Developer Tools ve Performance sekmesini aktif kullanın
- Bundle analizi yaparak kod boyutunu kontrol altında tutun
- Modern araçları ve patterns'ları takip edin
Faydalı Kaynaklar
Not: Performans optimizasyonu sürekli bir süreçtir. Uygulamanızın ihtiyaçlarına göre bu teknikleri uyarlayın ve düzenli olarak performans metriklerinizi takip edin.