Exploring Infinite Possibilities on FrontEnd 🚀
Burak Sağlık
Search...

Wed Feb 19 2025

Her Kıdemli React Geliştiricisinin Bilmesi Gereken 10 Performans İpucu

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!


1. React.memo ile Bileşen Optimizasyonu

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.

2. useCallback ve useMemo ile Fonksiyon ve Değerleri Önbelleğe Alma

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.

  • useCallback : Belirli bir fonksiyonun yeniden oluşturulmasını engellemek için kullanılır. Yani, fonksiyon yalnızca bağımlı olduğu değerler değiştiğinde yeniden oluşturulur. Aksi takdirde, aynı fonksiyon referansı kullanılır.
const memoizedCallback = useCallback(() => {
  // Fonksiyon içeriği
}, [dependencies]);
  • useMemo : Belirli bir değerin yeniden hesaplanmasını engellemek için kullanılır. Yani, sadece bağımlı olduğu değerler değiştiğinde yeniden hesaplanır. Aksi takdirde, önceki hesaplanmış değer tekrar kullanılır.
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;

3. Lazy Loading ile Bileşen Yükleme

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 Nedir?

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.

4. Virtual Listeler ile Büyük Veri Setlerini Yönetme

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! 🚀

5. Profiler ile Performans Analizi

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>
  );
}

6. Context API ile Veri Yönetimi

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! 🚀

7. Web Workers ile Ağır Hesaplamaları Arka Planda Çalıştırma

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 Nedir?

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.

Web Workers Nasıl Kullanılır?
  1. Worker Dosyası Oluşturma
  • Öncelikle bir worker dosyası oluşturulur (worker.js):
self.onmessage = function (event) {
  let result = 0;
  for (let i = 0; i < event.data; i++) {
    result += i;
  }
  self.postMessage(result);
};
  1. Worker'ı Ana Thread'de Kullanma
  • Ana JavaScript dosyanızda Web Worker'ı başlatabilirsiniz:
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. 🚀

8. Optimize Edilmiş State Yönetimi

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.

Popüler State Yönetimi Çözümleri

1. Redux

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.

  • ✔ Avantajları: Predictable state, büyük ölçekli uygulamalara uygun
  • ❌ Dezavantajları: Fazla boilerplate(kalıp) kod, karmaşık yapı
2. Recoil

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.

  • ✔ Avantajları: Minimal yapı, React ile doğal uyum
  • ❌ Dezavantajları: Henüz olgunlaşma aşamasında
3. Zustand

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.

  • ✔ Avantajları: Hafif, performans dostu, kolay kullanım
  • ❌ Dezavantajları: Büyük ölçekli uygulamalarda bazı sınırlamalar olabilir

Zustand ile Basit Bir Örnek

Ö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. 🚀

9. Error Boundaries ile Hata Yönetimi

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.

10. React Code Splitting ile Paket Boyutunu Azaltma

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!

Burak Sağlık

Burak Saglik

©2024 Desing and Developed by @Burak Sağlık

All rights reserved