React useEffect cleanup fonksiyonu, bileşenin bellekten kaldırıldığında veya yeniden render edildiğinde yan etkileri temizlemek için kullanılır. Bu fonksiyon, özellikle API abonelikleri, zamanlayıcılar (timer), event listener'lar ve async işlemlerde kritik öneme sahiptir. Doğru kullanılmadığında bellek sızıntıları ve uygulama performans sorunları ortaya çıkar.
useEffect hook'u, React'in functional component'lerinde yan etkileri yönetmenin standart yoludur. Cleanup fonksiyonu ise useEffect'in ikinci parametresi olan bağımlılık dizisine göre tetiklenir. Bu yazıda, cleanup fonksiyonunun nasıl çalıştığını, hangi durumlarda kullanılması gerektiğini ve sık yapılan hataları adım adım inceleyeceğiz.
useEffect Cleanup Fonksiyonu Nedir ve Neden Önemlidir?
useEffect, componentDidMount, componentDidUpdate ve componentWillUnmount mantığını tek bir fonksiyonda birleştirir. Cleanup fonksiyonu, useEffect'in döndürdüğü fonksiyondur ve bileşen DOM'dan kaldırıldığında (unmount) veya bağımlılıklar değiştiğinde bir sonraki effect çalışmadan önce çağrılır. Bu sayede kaynaklar düzgün bir şekilde serbest bırakılır.
Bir Zamanlayıcı Örneği
Aşağıda, her saniye artan bir sayaç örneği gösterilmiştir. Cleanup fonksiyonu olmadan, bileşen her render edildiğinde yeni bir setInterval oluşur ve eski timer'lar temizlenmez. Bu durum bellek sızıntısına yol açar.
import React, { useState, useEffect } from 'react';
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
// Cleanup fonksiyonu
return () => clearInterval(interval);
}, []);
return <div>{count}</div>;
}Yukarıdaki örnekte, useEffect yalnızca bileşen ilk kez render edildiğinde çalışır (boş bağımlılık dizisi sayesinde). Cleanup fonksiyonu bileşen unmount olduğunda interval'i temizler, böylece bellek sızıntısı önlenir.
Hangi Durumlarda Cleanup Fonksiyonu Gereklidir?
Cleanup fonksiyonu aşağıdaki senaryolarda zorunludur:
- Abonelikler (Subscriptions): WebSocket, Redux store, Firebase gibi harici kaynaklara yapılan abonelikler.
- Zamanlayıcılar (setTimeout, setInterval): Zamanlanmış görevler iptal edilmelidir.
- Event Listener'lar: addEventListener ile eklenen dinleyiciler removeEventListener ile kaldırılmalıdır.
- Async İşlemler: API istekleri gibi işlemler, bileşen unmount olduğunda iptal edilmelidir.
Bu noktada, React useState Hook ile State Yönetimi başlıklı yazımızda state yönetiminin püf noktalarını bulabilirsiniz. Cleanup fonksiyonu da benzer şekilde dikkat gerektirir.
Async İşlemlerde Cleanup: AbortController Kullanımı
Modern JavaScript, AbortController API'si ile fetch isteklerini iptal etmeyi sağlar. useEffect içinde async bir işlem başlatıldığında, cleanup fonksiyonunda iptal sinyali gönderilmelidir.
useEffect(() => {
const controller = new AbortController();
const signal = controller.signal;
fetch('/api/data', { signal })
.then(response => response.json())
.then(data => setData(data))
.catch(err => {
if (err.name !== 'AbortError') console.error(err);
});
return () => controller.abort();
}, []);Bu yaklaşım, bileşen unmount olduğunda gereksiz ağ isteklerini engeller ve bellek sızıntılarını önler. Ayrıca, bileşenin güncel olmayan state'e yazmasını da engeller.
Bağımlılık Dizisi (Dependency Array) ve Cleanup İlişkisi
useEffect'in bağımlılık dizisi, cleanup fonksiyonunun ne zaman çalışacağını belirler. Bağımlılıklar değiştiğinde önce eski effect'in cleanup'i çalışır, ardından yeni effect devreye girer. Bu mekanizma sayesinde her effect kendi kaynaklarını yönetebilir.
Örneğin, bir prop değiştiğinde eski abonelik iptal edilir ve yeni prop ile yeni bir abonelik başlatılır. Bu desen, dinamik veri akışlarında yaygındır.
useEffect(() => {
const subscription = subscribeToUser(userId);
return () => subscription.unsubscribe();
}, [userId]);Bağımlılık dizisini boş bırakmak ([]) yalnızca mount ve unmount sırasında çalışmasını sağlar. Eğer bağımlılıkları doğru belirtmezseniz, cleanup beklendiği gibi çalışmayabilir. Bu konuda React useState Hook ile State Yönetimi: Sık Yapılan Hatalar ve Doğru Kullanım yazımızdaki hata senaryolarına benzer durumlar yaşanabilir.
Sık Yapılan Hatalar ve Çözümleri
- Cleanup fonksiyonunu unutmak: Zamanlayıcı veya abonelik içeren her useEffect için cleanup yazmayı unutmayın.
- Async fonksiyonu doğrudan useEffect'e vermek: useEffect async olamaz. Bunun yerine içinde async bir fonksiyon tanımlayıp çağırın.
- Bağımlılık dizisini yanlış belirtmek: Eksik veya fazla bağımlılık, beklenmeyen davranışlara yol açar. ESLint react-hooks/exhaustive-deps kuralını etkinleştirin.
- Cleanup içinde state güncellemek: Unmount sırasında state güncellemek uyarıya neden olur. Bunun yerine ref kullanabilirsiniz.
Table: useEffect Cleanup Kullanım Senaryoları
| Yan Etki Türü | Cleanup Yöntemi | Örnek |
|---|---|---|
| Zamanlayıcı | clearInterval / clearTimeout | setInterval için clearInterval |
| Event Listener | removeEventListener | window.addEventListener için removeEventListener |
| API İsteği | AbortController.abort() | fetch ile AbortController |
| WebSocket | WebSocket.close() | new WebSocket için close |
Doğru cleanup yazmak, React uygulamalarının performansı ve güvenilirliği için kritiktir. Unutmayın, bileşen unmount olduktan sonra çalışan hiçbir effect kalmamalıdır. Bu konuda daha fazla bilgi için React useState Hook ile State Yönetimi rehberimize de göz atabilirsiniz.
Sık Sorulan Sorular
useEffect cleanup fonksiyonu ne zaman çalışır?
Cleanup fonksiyonu, bileşen DOM'dan kaldırıldığında (unmount) veya bağımlılıklar değiştiğinde bir sonraki useEffect çalışmadan önce çağrılır. Bu sayede kaynaklar düzgün bir şekilde temizlenir.
Async işlemlerde cleanup nasıl yapılır?
Async işlemlerde AbortController kullanarak fetch isteklerini iptal edebilirsiniz. useEffect içinde controller.abort() çağrısı ile cleanup sağlanır.
Cleanup fonksiyonu olmazsa ne olur?
Cleanup fonksiyonu olmadığında zamanlayıcılar, abonelikler veya event listener'lar bellekte kalır. Bu durum bellek sızıntılarına ve performans sorunlarına yol açar.
Bağımlılık dizisi boş olan useEffect'te cleanup gerekli mi?
Evet, bağımlılık dizisi boş olsa bile bileşen unmount olduğunda kaynakları temizlemek için cleanup fonksiyonu gereklidir.

