Wed Feb 19 2025
Merhaba! Bugün, kıdemli bir JavaScript ve React geliştiricisi olarak edindiğim deneyimlerden yola çıkarak, uygulamaların performansını artırmak ve daha verimli kod yazmak için kullandığım 10 önemli ipucunu paylaşacağım. Bu ipuçları, gündelik hayatta karşılaştığımız sorunlara pratik çözümler sunuyor. Hadi başlayalım!
React Js de bileşenler, state veya props değiştiğinde yeniden render edilir. Ancak, bazı durumlarda bu gereksiz render işlemleri performans sorunlarına yol açabilir. Özellikle büyük uygulamalarda, React.memo kullanarak bileşenlerin gereksiz render edilmesini önleyebiliriz.
Örnek Senaryo:
Bir e-ticaret uygulamasında, ürün listesi bileşeni her seferinde yeniden render ediliyor ve bu da performansı düşürüyor. Bu durumu React.memo ile çözebiliriz.
import React from "react";
const ProductList = React.memo(({ products }) => {
console.log("ProductList rendered!");
return (
<ul>
{products.map((product) => (
<li key={product.id}>{product.name}</li>
))}
</ul>
);
});
export default ProductList;
Bu sayede, products değişmediği sürece bileşen yeniden render edilmeyecek.
React'te fonksiyonlar ve hesaplama gerektiren değerler, her render sırasında yeniden oluşturulur. Bu durum, özellikle büyük uygulamalarda performans sorunlarına neden olabilir. useCallback ve useMemo ile bu sorunu çözebiliriz.
const memoizedCallback = useCallback(() => {
// Fonksiyon içeriği
}, [dependencies]);
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Örnek Senaryo:
Bir todo uygulamasında, her yeni görev eklendiğinde filtreleme fonksiyonu yeniden oluşturuluyor. Bu durumu useCallback ile optimize edebiliriz.
import React, { useCallback } from "react";
const TodoList = ({ todos, filter }) => {
const filteredTodos = useCallback(() => {
return todos.filter((todo) => todo.status === filter);
}, [todos, filter]);
return (
<ul>
{filteredTodos().map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
};
export default TodoList;
Modern web uygulamalarının büyük bir kısmı, kullanıcı deneyimini iyileştirmek için performans optimizasyonlarına odaklanıyor. Sayfanın ilk yüklenme süresini düşürmek ve gereksiz yüklenmeleri engellemek için Lazy Loading (Tembel Yükleme) tekniği oldukça etkili bir yöntem. Bu yöntem sayesinde bileşenleri ilk başta yüklemek yerine, sadece ihtiyaç duyulduğunda yüklenmesini sağlayabiliriz.
Lazy Loading, gerektiğinde yükleme anlamına gelir. React uygulamalarında, ilk yüklenme anında tüm bileşenleri yüklemek yerine, kullanıcının ihtiyaç duyduğu bileşenleri dinamik olarak yüklemek mantığına dayanır. Bu, uygulamanın performansını iyileştirir, sayfanın daha hızlı yüklenmesini sağlar ve gereksiz kaynak tüketimini azaltır.
Örnek Senaryo:
Normalde bir bileşeni doğrudan import ederken şu şekilde kullanıyoruz:
import ProductList from "./ProductList";
Ancak Lazy Loading ile bu bileşenin yalnızca ihtiyaç duyulduğunda yüklenmesini sağlayabiliriz:
import React, { lazy, Suspense } from "react";
// Bileşenin lazy load edilmesi
const ProductList = lazy(() => import("./ProductList"));
function App() {
return (
<div>
<h1>Lazy Loading Örneği</h1>
<Suspense fallback={<div>Yükleniyor...</div>}>
<ProductList />
</Suspense>
</div>
);
}
export default App;
📌 Kodun Mantığı React.lazy() fonksiyonu, bileşenin yalnızca ihtiyaç duyulduğunda import edilmesini sağlar. Suspense bileşeni, bileşen yüklenene kadar bir "fallback" (geçici içerik) gösterir. fallback ifadesi sayesinde, bileşen yüklenirken kullanıcıya gösterilecek bir mesaj veya loading animasyonu ekleyebiliriz.
Virtual Listeler, büyük veri setlerini işlemek için kullanılan bir teknik olup, yalnızca kullanıcının görüntülediği öğeleri render etmeyi sağlar. Yani, uzun bir listeyi tamamen DOM'a eklemek yerine, yalnızca ekranda görünen kısmını oluşturur ve kaydırma işlemiyle birlikte dinamik olarak yeni öğeleri yükler. Bu yöntem sayesinde, hafıza kullanımı azalır, sayfa daha hızlı yüklenir ve kullanıcı deneyimi iyileştirilir.Özellikle düşük kaynaklara sahip cihazlarda yüksek performanslı bir deneyim sunar.
Örnek Senaryo:
Bir sosyal medya uygulamasında, kullanıcının takipçi listesi binlerce öğe içeriyor olablir.
import { FixedSizeList } from "react-window";
const FollowerList = ({ followers }) => {
const Row = ({ index, style }) => (
<div style={style}>{followers[index].name}</div>
);
return (
<FixedSizeList height={300} itemCount={followers.length} itemSize={35}>
{Row}
</FixedSizeList>
);
};
export default FollowerList;
Virtual Listeler, büyük veri setlerini yönetmenin en verimli yollarından biridir. React gibi modern kütüphanelerde react-window veya react-virtualized kullanarak, performans kaybı yaşamadan büyük listeleri yönetebiliriz.
Özellikle büyük ölçekli uygulamalarda sayfa yüklenme süresini azaltmak, kullanıcı deneyimini iyileştirmek ve gereksiz bellek kullanımını önlemek için Virtual List kullanımı kaçınılmazdır. Eğer uygulamanızda büyük veri setleriyle çalışıyorsanız, mutlaka denemelisiniz! 🚀
React Profiler, bileşenlerin render sürelerini ölçmek ve performans sorunlarını tespit etmek için harika bir araçtır. Kullanımı oldukça kolaydır; performans sorunu olduğunu düşündüğümüz yerlerde kullanarak verileri inceleyebiliriz.
import { Profiler } from "react";
function onRenderCallback(
id,
phase,
actualDuration,
baseDuration,
startTime,
commitTime
) {
console.log(`${id} render süresi: ${actualDuration}ms`);
}
function Dashboard() {
return (
<Profiler id="Dashboard" onRender={onRenderCallback}>
<FollowerList />
<ProductList />
</Profiler>
);
}
Context API, React'in dahili bir mekanizmasıdır ve bileşenler arası veri paylaşımını kolaylaştırarak prop drilling sorununu ortadan kaldırır. Redux gibi harici kütüphanelere ihtiyaç duymadan, global state yönetimini daha basit hale getirir.
Örnek Kod:
Bir tema değiştirme özelliği eklemek istiyoruz.
const ThemeContext = React.createContext();
function App() {
const [theme, setTheme] = React.useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<MainContent />
</ThemeContext.Provider>
);
}
function Header() {
const { theme, setTheme } = React.useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Temayı Değiştir
</button>
);
}
Context API, React projelerinde basit ve etkili bir global state yönetimi sağlar. Küçük ve orta ölçekli projelerde Redux veya diğer state yönetim kütüphanelerine alternatif olarak kullanılabilir. Veri yönetimini daha temiz ve okunabilir hale getirmek için Context API'den faydalanabilirsiniz! 🚀
Web uygulamalarında ağır hesaplamalar ve uzun süren işlemler, ana iş parçacığını (main thread) meşgul ederek kullanıcı arayüzünün donmasına neden olabilir. Web Workers, bu tür işlemleri arka planda çalıştırarak uygulamanın performansını artıran güçlü bir teknolojidir.
Web Workers, JavaScript kodunu ana iş parçacığından bağımsız olarak çalıştıran bir mekanizmadır. Tarayıcı, worker'ı ayrı bir iş parçacığında başlatarak, uzun süren işlemlerin ana thread'i bloke etmesini önler.
self.onmessage = function (event) {
let result = 0;
for (let i = 0; i < event.data; i++) {
result += i;
}
self.postMessage(result);
};
const worker = new Worker("worker.js");
worker.onmessage = function (event) {
console.log("Sonuç:", event.data);
};
worker.postMessage(1000000000); // Büyük bir sayı göndererek hesaplama başlatılır.
Bir veri analiz uygulamasında, büyük veri setlerini filtrelemek veya karmaşık hesaplamalar yapmak Web Workers sayesinde ana iş parçacığını yormadan gerçekleştirilebilir.
Web Workers, büyük ve karmaşık işlemleri arka planda çalıştırarak kullanıcı deneyimini iyileştiren önemli bir teknolojidir. Performans gerektiren uygulamalarda mutlaka değerlendirilmelidir. 🚀
Modern web uygulamalarında performanslı ve ölçeklenebilir state yönetimi büyük önem taşır. Gereksiz render işlemlerini önlemek, bellek kullanımını optimize etmek ve kodun sürdürülebilirliğini sağlamak için doğru state yönetimi yaklaşımını seçmek kritik bir karardır.
Redux, global state yönetimi için kullanılan en popüler kütüphanelerden biridir. Tek yönlü veri akışı ve immutable state yapısı ile karmaşık uygulamalar için uygundur. Ancak boilerplate(kalıp) kod miktarı fazla olabilir.
Recoil, React ekosistemiyle doğal bir uyum sağlayan, daha hafif ve esnek bir state yönetim aracıdır. Atom ve Selector yapıları ile parçalı state yönetimini destekler.
Zustand, minimal ve performans odaklı bir state yönetim kütüphanesidir. Redux’a kıyasla çok daha basit bir API sunar ve selector kullanımı sayesinde gereksiz render işlemlerini önler.
Örnek Kod:
Zustand kullanarak basit bir sayaç uygulaması oluşturalım:
import create from "zustand";
const useStore = create((set) => ({
count: 0,
increase: () => set((state) => ({ count: state.count + 1 })),
}));
function Counter() {
const { count, increase } = useStore();
return (
<div>
<p>Sayaç: {count}</p>
<button onClick={increase}>Arttır</button>
</div>
);
}
export default Counter;
Eğer küçük ve orta ölçekli projelerde basit, hafif ve performanslı bir çözüm arıyorsanız Zustand iyi bir alternatif olabilir. Redux daha büyük projelerde güçlü bir yapı sunarken, Recoil ise React ile daha doğal bir entegrasyon sağlar. Hangi yöntemin kullanılacağı, projenin ihtiyaçlarına ve ölçeğine bağlıdır. 🚀
React Js de uygulama geliştirdiğimizde, hata yönetimi çok önemlidir. Kullanıcı deneyimini kesintiye uğratmamak için hataların doğru bir şekilde ele alınması gerekir. React, hata sınırları (Error Boundaries) kullanarak, bileşenlerin render, yaşam döngüsü veya event handlerlarında oluşabilecek hataları yakalamamıza yardımcı olur.
Error Boundary, hata meydana geldiğinde bir yedek UI render eder. Bu, uygulamanın geri kalan kısmının çalışmaya devam etmesini sağlar. Error Boundary, yalnızca sınıf bileşenlerinde kullanılabilir.
İşte basit bir Error Boundary örneği:
import React, { Component } from "react";
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Hata oluştuğunda state güncellenir
return { hasError: true };
}
componentDidCatch(error, info) {
// Hata loglama işlemleri yapılabilir. Burda isterniz hataları bir servis ile db Kayıt edebilirsiz
console.error("Hata: ", error);
console.error("Hata bilgisi: ", info);
}
render() {
if (this.state.hasError) {
// Hata durumunda kulanıcıya isteğe bağlı farklı bir UI gösterilebilir
return <h1>Bir şeyler ters gitti.</h1>;
}
return this.props.children;
}
}
export default ErrorBoundary;
Kullanımı:
import React from "react";
import ErrorBoundary from "./ErrorBoundary";
function MyComponent() {
throw new Error("Hata oluştu!"); // Hata simülasyonu
return <div>Bu render edilemez çünkü hata oluştu</div>;
}
function App() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
);
}
export default App;
Yukarıdaki örnekte, MyComponent bileşeninde bir hata fırlatılıyor. Bu hata, ErrorBoundary tarafından yakalanıyor ve kullanıcıya daha anlamlı bir mesaj gösteriliyor. Error Boundary, uygulamanın diğer kısmını etkilenmeden çalıştırmaya devam eder.
React’te code splitting, uygulamanın başlangıçta yüklenen JavaScript dosyasını küçültmek için kullanılan bir tekniktir. Bu sayede sadece gerekli olan kod parçaları yüklenir, böylece uygulamanın ilk yüklenme süresi hızlanır ve performans artar.
React Router ile de code splitting yapılabilir. Yalnızca o an ziyaret edilen sayfanın bileşeni yüklenir, bu da sayfa geçişlerini hızlandırır.
Örnek Kod:
import React, { Suspense } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
const Home = React.lazy(() => import("./Home"));
const About = React.lazy(() => import("./About"));
function App() {
return (
<Router>
<Suspense fallback={<div>Yükleniyor...</div>}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Switch>
</Suspense>
</Router>
);
}
export default App;
Sonuç olarak, code splitting ile büyük dosyalar yalnızca ihtiyaç duyulduğunda yüklenir ve uygulamanızın performansı ciddi şekilde iyileşir.
Umarım bu ipuçları, React uygulamalarınızın performansını artırmanıza yardımcı olur! Herhangi bir sorunuz varsa bana ulaşmaktan çekinmeyin. Bir sonraki yazıda görüşmek üzere!
All rights reserved