Türkçe

Bellek sızıntılarını önlemek ve uygulamanızın performansını optimize etmek için React effect temizleme fonksiyonlarını nasıl etkili bir şekilde kullanacağınızı öğrenin. React geliştiricileri için kapsamlı bir rehber.

React Effect Temizliği: Bellek Sızıntısı Önlemede Uzmanlaşma

React'in useEffect hook'u, fonksiyonel bileşenlerinizdeki yan etkileri yönetmek için güçlü bir araçtır. Ancak, doğru kullanılmadığında bellek sızıntılarına yol açarak uygulamanızın performansını ve kararlılığını etkileyebilir. Bu kapsamlı rehber, React effect temizliğinin inceliklerine derinlemesine inecek ve size bellek sızıntılarını önlemek ve daha sağlam React uygulamaları yazmak için gerekli bilgi ve pratik örnekleri sunacaktır.

Bellek Sızıntıları Nedir ve Neden Kötüdür?

Bellek sızıntısı, uygulamanızın bellek ayırdığı ancak artık ihtiyaç duyulmadığında bunu sisteme geri bırakmadığı durumlarda meydana gelir. Zamanla, bu serbest bırakılmayan bellek blokları birikerek giderek daha fazla sistem kaynağı tüketir. Web uygulamalarında bellek sızıntıları şu şekillerde kendini gösterebilir:

React'te bellek sızıntıları genellikle useEffect hook'ları içinde asenkron işlemler, abonelikler veya olay dinleyicileri ile uğraşırken meydana gelir. Bu işlemler, bileşen kaldırıldığında (unmount) veya yeniden render edildiğinde düzgün bir şekilde temizlenmezse, arka planda çalışmaya devam ederek kaynakları tüketebilir ve potansiyel olarak sorunlara neden olabilir.

useEffect ve Yan Etkileri Anlamak

Effect temizliğine dalmadan önce, useEffect'in amacını kısaca gözden geçirelim. useEffect hook'u, fonksiyonel bileşenlerinizde yan etkiler gerçekleştirmenize olanak tanır. Yan etkiler, dış dünya ile etkileşime giren işlemlerdir, örneğin:

useEffect hook'u iki argüman kabul eder:

  1. Yan etkiyi içeren bir fonksiyon.
  2. İsteğe bağlı bir bağımlılık dizisi.

Yan etki fonksiyonu, bileşen render edildikten sonra çalıştırılır. Bağımlılık dizisi, React'e effect'in ne zaman yeniden çalıştırılacağını söyler. Bağımlılık dizisi boşsa ([]), effect yalnızca ilk render'dan sonra bir kez çalışır. Bağımlılık dizisi belirtilmezse, effect her render'dan sonra çalışır.

Effect Temizliğinin Önemi

React'te bellek sızıntılarını önlemenin anahtarı, artık ihtiyaç duyulmayan yan etkileri temizlemektir. İşte bu noktada temizleme fonksiyonu devreye girer. useEffect hook'u, yan etki fonksiyonundan bir fonksiyon döndürmenize olanak tanır. Bu döndürülen fonksiyon, temizleme fonksiyonudur ve bileşen kaldırıldığında (unmount) veya effect yeniden çalıştırılmadan önce (bağımlılıklardaki değişiklikler nedeniyle) çalıştırılır.

İşte temel bir örnek:


import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log('Effect çalıştı');

    // Bu, temizleme fonksiyonudur
    return () => {
      console.log('Temizleme çalıştı');
    };
  }, []); // Boş bağımlılık dizisi: yalnızca mount edildiğinde bir kez çalışır

  return (
    

Sayı: {count}

); } export default MyComponent;

Bu örnekte, console.log('Effect çalıştı') bileşen mount edildiğinde bir kez çalışacaktır. console.log('Temizleme çalıştı') ise bileşen unmount edildiğinde çalışacaktır.

Effect Temizliği Gerektiren Yaygın Senaryolar

Effect temizliğinin çok önemli olduğu bazı yaygın senaryoları inceleyelim:

1. Zamanlayıcılar (setTimeout ve setInterval)

useEffect hook'unuzda zamanlayıcılar kullanıyorsanız, bileşen kaldırıldığında bunları temizlemek çok önemlidir. Aksi takdirde, zamanlayıcılar bileşen gittikten sonra bile çalışmaya devam ederek bellek sızıntılarına ve potansiyel olarak hatalara neden olur. Örneğin, döviz kurlarını belirli aralıklarla çeken otomatik güncellenen bir para birimi dönüştürücüsünü düşünün:


import React, { useState, useEffect } from 'react';

function CurrencyConverter() {
  const [exchangeRate, setExchangeRate] = useState(0);

  useEffect(() => {
    const intervalId = setInterval(() => {
      // Bir API'den döviz kuru çekmeyi simüle et
      const newRate = Math.random() * 1.2;  // Örnek: 0 ile 1.2 arasında rastgele bir kur
      setExchangeRate(newRate);
    }, 2000); // Her 2 saniyede bir güncelle

    return () => {
      clearInterval(intervalId);
      console.log('Interval temizlendi!');
    };
  }, []);

  return (
    

Güncel Döviz Kuru: {exchangeRate.toFixed(2)}

); } export default CurrencyConverter;

Bu örnekte, exchangeRate'i her 2 saniyede bir güncellemek için setInterval kullanılır. Temizleme fonksiyonu, bileşen kaldırıldığında interval'ı durdurmak için clearInterval kullanır, böylece zamanlayıcının çalışmaya devam etmesini ve bellek sızıntısına neden olmasını önler.

2. Olay Dinleyicileri

useEffect hook'unuzda olay dinleyicileri eklerken, bileşen kaldırıldığında bunları kaldırmanız gerekir. Bunu yapmamak, aynı öğeye birden fazla olay dinleyicisinin eklenmesine neden olarak beklenmedik davranışlara ve bellek sızıntılarına yol açabilir. Örneğin, farklı ekran boyutları için düzenini ayarlamak amacıyla pencere yeniden boyutlandırma olaylarını dinleyen bir bileşen hayal edin:


import React, { useState, useEffect } from 'react';

function ResponsiveComponent() {
  const [windowWidth, setWindowWidth] = useState(window.innerWidth);

  useEffect(() => {
    const handleResize = () => {
      setWindowWidth(window.innerWidth);
    };

    window.addEventListener('resize', handleResize);

    return () => {
      window.removeEventListener('resize', handleResize);
      console.log('Olay dinleyicisi kaldırıldı!');
    };
  }, []);

  return (
    

Pencere Genişliği: {windowWidth}

); } export default ResponsiveComponent;

Bu kod, pencereye bir resize olay dinleyicisi ekler. Temizleme fonksiyonu, bileşen kaldırıldığında dinleyiciyi kaldırmak için removeEventListener kullanır ve bellek sızıntılarını önler.

3. Abonelikler (Websockets, RxJS Observable'ları vb.)

Bileşeniniz websockets, RxJS Observable'ları veya diğer abonelik mekanizmalarını kullanarak bir veri akışına abone oluyorsa, bileşen kaldırıldığında abonelikten çıkmak çok önemlidir. Abonelikleri aktif bırakmak, bellek sızıntılarına ve gereksiz ağ trafiğine yol açabilir. Bir bileşenin gerçek zamanlı hisse senedi fiyatları için bir websocket akışına abone olduğu bir örneği ele alalım:


import React, { useState, useEffect } from 'react';

function StockTicker() {
  const [stockPrice, setStockPrice] = useState(0);
  const [socket, setSocket] = useState(null);

  useEffect(() => {
    // Bir WebSocket bağlantısı oluşturmayı simüle et
    const newSocket = new WebSocket('wss://example.com/stock-feed');
    setSocket(newSocket);

    newSocket.onopen = () => {
      console.log('WebSocket bağlandı');
    };

    newSocket.onmessage = (event) => {
      // Hisse senedi fiyat verisi almayı simüle et
      const price = parseFloat(event.data);
      setStockPrice(price);
    };

    newSocket.onclose = () => {
      console.log('WebSocket bağlantısı kesildi');
    };

    newSocket.onerror = (error) => {
      console.error('WebSocket hatası:', error);
    };

    return () => {
      newSocket.close();
      console.log('WebSocket kapatıldı!');
    };
  }, []);

  return (
    

Hisse Fiyatı: {stockPrice}

); } export default StockTicker;

Bu senaryoda, bileşen bir hisse senedi akışına WebSocket bağlantısı kurar. Temizleme fonksiyonu, bileşen kaldırıldığında bağlantıyı kapatmak için socket.close() kullanır, böylece bağlantının aktif kalmasını ve bellek sızıntısına neden olmasını önler.

4. AbortController ile Veri Çekme

useEffect içinde veri çekerken, özellikle yanıt vermesi biraz zaman alabilecek API'lerden, istek tamamlanmadan bileşen kaldırılırsa fetch isteğini iptal etmek için bir AbortController kullanmalısınız. Bu, gereksiz ağ trafiğini ve bileşen kaldırıldıktan sonra durumunu güncellemekten kaynaklanan potansiyel hataları önler. İşte kullanıcı verilerini çeken bir örnek:


import React, { useState, useEffect } from 'react';

function UserProfile() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    const fetchData = async () => {
      try {
        const response = await fetch('https://api.example.com/user', { signal });
        if (!response.ok) {
          throw new Error(`HTTP hatası! durum: ${response.status}`);
        }
        const data = await response.json();
        setUser(data);
      } catch (err) {
        if (err.name === 'AbortError') {
          console.log('Fetch iptal edildi');
        } else {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      controller.abort();
      console.log('Fetch iptal edildi!');
    };
  }, []);

  if (loading) {
    return 

Yükleniyor...

; } if (error) { return

Hata: {error.message}

; } return (

Kullanıcı Profili

İsim: {user.name}

E-posta: {user.email}

); } export default UserProfile;

Bu kod, veri alınmadan önce bileşen kaldırılırsa fetch isteğini iptal etmek için AbortController kullanır. Temizleme fonksiyonu, isteği iptal etmek için controller.abort()'u çağırır.

useEffect'deki Bağımlılıkları Anlamak

useEffect'deki bağımlılık dizisi, effect'in ne zaman yeniden çalıştırılacağını belirlemede çok önemli bir rol oynar. Ayrıca temizleme fonksiyonunu da etkiler. Beklenmedik davranışlardan kaçınmak ve uygun temizliği sağlamak için bağımlılıkların nasıl çalıştığını anlamak önemlidir.

Boş Bağımlılık Dizisi ([])

Boş bir bağımlılık dizisi ([]) sağladığınızda, effect yalnızca ilk render'dan sonra bir kez çalışır. Temizleme fonksiyonu yalnızca bileşen kaldırıldığında çalışacaktır. Bu, bir websocket bağlantısını başlatmak veya genel bir olay dinleyicisi eklemek gibi yalnızca bir kez kurulması gereken yan etkiler için kullanışlıdır.

Değerli Bağımlılıklar

Değerler içeren bir bağımlılık dizisi sağladığınızda, effect dizideki değerlerden herhangi biri değiştiğinde yeniden çalıştırılır. Temizleme fonksiyonu, effect yeniden çalıştırılmadan *önce* çalıştırılır, bu da yenisini kurmadan önce önceki effect'i temizlemenize olanak tanır. Bu, bir kullanıcı kimliğine göre veri çekmek veya bir bileşenin durumuna göre DOM'u güncellemek gibi belirli değerlere bağlı olan yan etkiler için önemlidir.

Bu örneği düşünün:


import React, { useState, useEffect } from 'react';

function DataFetcher({ userId }) {
  const [data, setData] = useState(null);

  useEffect(() => {
    let didCancel = false;

    const fetchData = async () => {
      try {
        const response = await fetch(`https://api.example.com/users/${userId}`);
        const result = await response.json();
        if (!didCancel) {
          setData(result);
        }
      } catch (error) {
        console.error('Veri çekerken hata:', error);
      }
    };

    fetchData();

    return () => {
      didCancel = true;
      console.log('Fetch iptal edildi!');
    };
  }, [userId]);

  return (
    
{data ?

Kullanıcı Verisi: {data.name}

:

Yükleniyor...

}
); } export default DataFetcher;

Bu örnekte, effect userId prop'una bağlıdır. Effect, userId her değiştiğinde yeniden çalıştırılır. Temizleme fonksiyonu, didCancel bayrağını true olarak ayarlar, bu da bileşen kaldırıldıktan veya userId değiştikten sonra fetch isteği tamamlansa bile durumun güncellenmesini önler. Bu, "Can't perform a React state update on an unmounted component" (Kaldırılmış bir bileşen üzerinde React durum güncellemesi yapılamaz) uyarısını önler.

Bağımlılık Dizisini Atlamak (Dikkatli Kullanın)

Bağımlılık dizisini atlarsanız, effect her render'dan sonra çalışır. Bu genellikle performans sorunlarına ve sonsuz döngülere yol açabileceğinden önerilmez. Ancak, prop'ların veya state'in en son değerlerine effect içinde bunları açıkça bağımlılık olarak listelemeden erişmeniz gerektiği gibi nadir durumlar olabilir.

Önemli: Bağımlılık dizisini atlarsanız, herhangi bir yan etkiyi temizleme konusunda *son derece* dikkatli olmalısınız. Temizleme fonksiyonu *her* render'dan önce çalıştırılacaktır, bu da verimsiz olabilir ve doğru şekilde ele alınmazsa potansiyel olarak sorunlara neden olabilir.

Effect Temizliği için En İyi Uygulamalar

Effect temizliği kullanırken izlenecek bazı en iyi uygulamalar şunlardır:

Bellek Sızıntılarını Tespit Etme Araçları

React uygulamalarınızdaki bellek sızıntılarını tespit etmenize yardımcı olabilecek birkaç araç vardır:

Sonuç

React effect temizliğinde uzmanlaşmak, sağlam, performanslı ve bellek açısından verimli React uygulamaları oluşturmak için çok önemlidir. Effect temizliği prensiplerini anlayarak ve bu kılavuzda belirtilen en iyi uygulamaları takip ederek bellek sızıntılarını önleyebilir ve sorunsuz bir kullanıcı deneyimi sağlayabilirsiniz. Her zaman yan etkileri temizlemeyi, bağımlılıklara dikkat etmeyi ve kodunuzdaki olası bellek sızıntılarını tespit edip gidermek için mevcut araçları kullanmayı unutmayın.

Bu teknikleri özenle uygulayarak, React geliştirme becerilerinizi yükseltebilir ve yalnızca işlevsel değil, aynı zamanda performanslı ve güvenilir uygulamalar oluşturarak dünya çapındaki kullanıcılar için daha iyi bir genel kullanıcı deneyimine katkıda bulunabilirsiniz. Bellek yönetimine bu proaktif yaklaşım, deneyimli geliştiricileri ayırt eder ve React projelerinizin uzun vadeli sürdürülebilirliğini ve ölçeklenebilirliğini sağlar.

React Effect Temizliği: Bellek Sızıntısı Önlemede Uzmanlaşma | MLOG