aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Web Geliştirme

React useEffect Hook'u: Doğru Kullanım Rehberi

React useEffect kancası, bileşenlerinizi React'in dışındaki dünyaya — ağ istekleri, abonelikler, zamanlayıcılar, tarayıcı API'leri — bağlamak için kullanılır. Güçlüdür ama yanlış kullanıldığında sonsuz döngüler, bellek sızıntıları ve hata ayıklaması zor "hayalet" davranışlar üretir. Bu rehberde bağımlılık dizisini, cleanup mantığını ve en sık yapılan hataları gerçek örneklerle ele alıyoruz.

useEffect ne işe yarar?

Bir efekt, render sonrası çalışan bir yan etkidir. React önce ekrana çizer, sonra efektinizi çalıştırır. Bu yüzden efektler; bileşenin render çıktısını doğrudan etkilemeyen, dışarıyla konuşan işler için uygundur:

  • Sunucudan veri çekme (fetch, axios)
  • WebSocket veya olay aboneliği kurma
  • setInterval / setTimeout başlatma
  • Doküman başlığını veya tarayıcı API'lerini güncelleme

Sadece bir değeri başka bir değerden hesaplıyorsanız efekte ihtiyacınız yoktur — bunu render sırasında yapın. Efekt, "render dışı" bir şeye dokunduğunuzda gereklidir.

Bağımlılık dizisi: kalbi burası

useEffect üç biçimde çalışır ve farkı belirleyen ikinci argüman olan bağımlılık dizisidir:

// 1) Her render'dan sonra çalışır
useEffect(() => {
  console.log('her render');
});

// 2) Sadece ilk mount'ta çalışır
useEffect(() => {
  console.log('bir kez');
}, []);

// 3) userId her değiştiğinde çalışır
useEffect(() => {
  fetchUser(userId);
}, [userId]);

Kural basit: efekt içinde kullandığınız her reaktif değer (prop, state, fonksiyon) bağımlılık dizisinde yer almalıdır. Bir bağımlılığı atlamak, efektin eski (stale) değerlerle çalışmasına yol açar. React ekibinin eslint-plugin-react-hooks eklentisindeki exhaustive-deps kuralı bunu sizin için yakalar; uyarıyı susturmak yerine kök nedeni çözün.

Cleanup fonksiyonu ve bellek sızıntıları

Bir efekt kalıcı bir şey kurarsa (abonelik, zamanlayıcı, dinleyici), onu temizlemekten de siz sorumlusunuz. Efekt fonksiyonundan döndürdüğünüz fonksiyon, bileşen DOM'dan kaldırılmadan önce ve efekt bir sonraki sefer yeniden çalışmadan önce çağrılır:

useEffect(() => {
  const id = setInterval(() => {
    setSeconds((s) => s + 1);
  }, 1000);

  return () => clearInterval(id); // cleanup
}, []);

Cleanup yazmazsanız, her yeniden çalıştırmada yeni bir setInterval birikir ve bileşen unmount olduktan sonra bile çalışmaya devam eder — klasik bir bellek sızıntısı. Olay dinleyicileri için aynı kural geçerlidir:

useEffect(() => {
  const onResize = () => setWidth(window.innerWidth);
  window.addEventListener('resize', onResize);
  return () => window.removeEventListener('resize', onResize);
}, []);

Yarış koşulları (race conditions)

Veri çekerken sık görülen bir tuzak şudur: kullanıcı hızlıca farklı kayıtlara tıklarsa, eski istek geç tamamlanıp yeni veriyi ezebilir. Cleanup içinde bir bayrak (veya AbortController) kullanarak bunu önleyin:

useEffect(() => {
  let active = true;
  fetch(`/api/users/${userId}`)
    .then((r) => r.json())
    .then((data) => {
      if (active) setUser(data);
    });
  return () => {
    active = false; // eski istek artık state'i güncellemez
  };
}, [userId]);

Modern tarayıcılarda AbortController ile isteği gerçekten iptal etmek daha temizdir. Daha büyük uygulamalarda TanStack Query veya SWR gibi kütüphaneler bu yarış koşullarını ve önbelleklemeyi sizin yerinize halleder.

En sık yapılan hatalar

  • Bağımlılığı atlamak: Diziye eklemediğiniz değerler donar (stale closure). Çözüm: exhaustive-deps kuralına uyun.
  • Boş dizi ile sonsuz döngü: Aslında sorun çoğu zaman tersidir — diziye her render'da yeniden oluşan bir nesne/dizi/fonksiyon koymak efekti durmadan tetikler. Bu değerleri useMemo / useCallback ile sabitleyin.
  • Türetilmiş veriyi efekte koymak: Bir state'ten başka bir state hesaplamak için efekt kullanmayın; render sırasında hesaplayın.
  • Cleanup unutmak: Her abonelik/zamanlayıcı için temizleyici yazın.
  • async fonksiyonu doğrudan vermek: useEffect(async () => …) yanlıştır; efekt bir cleanup fonksiyonu döndürmeli, Promise değil. İçeride ayrı bir async fonksiyon tanımlayıp çağırın.

StrictMode neden efekti iki kez çalıştırır?

Geliştirme ortamında React 18+ StrictMode altında her efekti bilerek bir kez mount eder, hemen unmount eder ve tekrar mount eder. Amaç, cleanup'ınızın doğru yazıldığını ortaya çıkarmaktır. Efektiniz iki kez tetiklendiğinde "bug" diye paniklemeyin; cleanup'ı düzgün yazarsanız bu davranış zararsızdır ve üretim derlemesinde gerçekleşmez.

Sık Sorulan Sorular

useEffect ile useLayoutEffect arasındaki fark nedir?

useEffect tarayıcı boyamayı tamamladıktan sonra asenkron çalışır; çoğu durumda doğru seçimdir. useLayoutEffect ise DOM güncellendikten sonra ama boyamadan önce senkron çalışır; sadece ölçüm yapıp düzeni anında ayarlamanız gerektiğinde (örneğin bir tooltip konumlandırma) kullanın, aksi halde performansı düşürebilir.

Bağımlılık dizisini hiç vermezsem ne olur?

İkinci argümanı tamamen atlarsanız efekt her render sonrası çalışır. Bu nadiren istenir ve genellikle [] veya gerçek bağımlılıkları yazmak istediğiniz anlamına gelir.

Veri çekmek için en iyi yöntem efekt mi?

Küçük durumlarda evet, ama TanStack Query veya SWR gibi kütüphaneler önbellekleme, yeniden deneme ve yarış koşullarını otomatik yönettiği için çoğu projede daha sağlam bir seçimdir.

React mimarinizde efektler kontrolden mi çıktı? Bileşenlerinizi gözden geçirip stale closure ve sızıntıları temizleyelim. Benimle iletişime geçin ve projenizi birlikte sağlamlaştıralım.

Bu kategorideki tüm yazılar →

Devamı için