React, bileşenlerinizin öngörülebilir olmasını ister. Ona aynı state ve prop'ları verirseniz, her seferinde aynı UI'ı çizmelidir. Ancak çoğu gerçek uygulama bu balonun içinde hayatta kalamaz. Dışarıya uzanmaları gerekir. Bir dashboard'un sunucudan taze verilere ihtiyacı vardır. Bir chat widget'ının mesajları dinlemesi gerekir. Bir timer'ın ilerlemesi gerekir. Bu işlemler yan etkilerdir (side effects) ve React'in render döngüsünün dışında yer alırlar. useEffect hook'u, bileşeninizin kendisinin dürüst kalması için bu karmaşık ve öngörülemeyen işleri koyduğunuz yerdir.

Yan Etkiler: useEffect İçinde Neler Yer Almalı

Bir yan etki, JSX döndürmenin ötesinde dünyayla temas kuran herhangi bir şeydir. React'in render aşaması saf (pure) olmalıdır. Veri çekmeye, global değişkenlere yazmaya veya DOM'a dinleyiciler (listeners) eklemeye başladığınızda, saf bölgeden dışarı çıkmış olursunuz.

Yaygın örnekler şunlardır:

  • Bir API'den veri çekmek
  • Timer veya interval kurulumu yapmak
  • window veya document nesnelerine event listener eklemek
  • Tarayıcı sekmesi başlığını güncellemek
  • WebSockets'e bağlanmak

Bu görevlerin ortak bir özelliği vardır: bileşeninizin return ifadesinin içinde veya ana render mantığı sırasında yer almazlar. setInterval gibi bir tarayıcı API'sini doğrudan render gövdesi içinde çağırmaya çalışmak, her render işleminde tetiklenecek, yinelenen timer'lar oluşturacak ve kafa karıştırıcı davranışlara yol açacaktır. useEffect, tam olarak bu işi izole etmek ve doğru zamanda çalıştırmak için vardır.

Bağımlılık Dizisi (Dependency Array) Zamanlamayı Nasıl Kontrol Eder?

useEffect'in ikinci argümanı bağımlılık dizisidir (dependency array) ve bu, class bileşenlerinden geçiş yapan geliştiriciler için en büyük kafa karışıklığı kaynağıdır. Bunu, React'in mevcut render'dan sonra efektinizi atlayıp atlamayacağına veya çalıştırıp çalıştırmayacağına karar vermek için izlediği bir değişken seti olarak düşünün.

Sürekli kullanacağınız üç desen vardır.

Hiç bağımlılık dizisi olmaması. Diziyi tamamen atlarsanız, React efektin ilk render dahil her bir render işleminden sonra çalışmasını istediğinizi varsayar. Bu, nadiren ihtiyacınız olan bir durumdur. Eğer efektiniz bir ağ isteği veya ağır bir DOM işlemi gerçekleştiriyorsa, bunu her tuş vuruşunda veya state değişikliğinde çalıştırmak performansı yerle bir edecektir. Bu deseni yalnızca herhangi bir prop veya state değişmiş olabileceği ve hangilerini belirleyemediğiniz için bir şeyi gerçekten yeniden çalıştırmanız gerektiğinde kullanın.

Boş bir dizi []. Bu, React'e efektin bileşen mount edildikten ve DOM hazır olduktan hemen sonra yalnızca bir kez çalışmasını söyler. Bu, başlangıç veri çekme işlemleri için doğru yerdir. Örneğin, bileşeniniz kullanıcı profil verilerini yüklüyorsa, bu isteğin her kullanıcı formla etkileşime girdiğinde değil, profil sayfası göründüğünde tam olarak bir kez çalışmasını istersiniz.

Belirli değişkenlerin bulunduğu bir dizi [count]. Bu, hassas bir araçtır. React, bu bağımlılıkların mevcut değerlerini son render'daki değerleriyle karşılaştırır. Eğer herhangi biri değiştiyse, efekt çalışır. Listede hiçbir şey değişmediyse, React efekti tamamen atlar.

Tarayıcı sekmesi başlığını bir state değişkeni ile senkronize ediyorsanız, o değişkeni bağımlılık dizisine koyarsınız. React, başlığı yalnızca o değer değiştiğinde güncelleyecektir. Diziden çıkarırsanız başlık güncel kalmaz. Alakasız state değişkenlerini eklerseniz, önemsiz değişiklikler için başlığı güncellemekle döngüleri boşa harcarsınız.

Temizlik (Cleanup) İsteğe Bağlı Değildir

Bazı efektler arkalarında iz bırakır. Bir timer saymaya devam eder. Bir event listener tetiklenmeye devam eder. Bir WebSocket açık kalır. Bileşeniniz unmount olduğunda veya bir efekt bağımlılıkları değiştiği için yeniden çalıştığında, React önceki efektin kalıntılarını otomatik olarak temizlemez. Bu sizin işinizdir.

useEffect içinden bir fonksiyon döndürerek bir temizlik (cleanup) fonksiyonu oluşturursunuz. React, bir sonraki efekti uygulamadan önce ve bileşen ekrandan ayrıldığında bir kez daha bu temizlik fonksiyonunu çağırır.

Temizliği şunlar için kullanmalısınız:

  • clearInterval veya clearTimeout ile interval veya timeout'ları temizlemek
  • window, document veya harici düğümlere (nodes) eklenen event listener'ları kaldırmak
  • Veri akışlarından (data streams) veya servislerden aboneliği iptal etmek (unsubscribing)

Bunu ihmal ederseniz bellek sızıntıları (memory leaks) ile karşılaşırsınız. Bir bileşen mount olur, bir scroll listener ekler, unmount olur ve listener kalmaya devam eder. Tarayıcı, callback fonksiyonunu ve onun referans verdiği DOM düğümlerini tutmaya devam eder. Zamanla, özellikle yoğun navigasyonun olduğu tek sayfa uygulamalarında (SPA), bu hayaletler birikir ve sekmeyi yavaşlatır. Çözüm genellikle sadece birkaç satırdır: eklediğiniz şeyi kaldıran bir fonksiyon döndürün.

Canlı Ortama (Production) Gönderilen Yaygın Hatalar

Deneyimli geliştiriciler bile daha basit bir seçenek varken useEffect kullanmaya yönelebilirler. İşte kod incelemesi sırasında kırmızı bayrak kaldırması gereken üç desen.

Sonsuz döngüler. Döngüyü kıran bir kontrol koşulunuz yoksa, eğer aynı değişken bağımlılık dizinizde (dependency array) yer alıyorsa, useEffect içinde asla bir state değişkenini güncellemeyin. Eğer count değerini okur, onu artırır ve count değerini bir bağımlılık olarak listelerseniz; React değişikliği görür, yeniden render eder, effect'i tekrar çalıştırır, tekrar artırır ve tarayıcıyı kilitler.

Gereksiz effect'ler. Mevcut props veya state'ten bir değer hesaplamak için useEffect kullanmayın. Eğer değeri render sırasında doğrudan türetebiliyorsanız, sadece bunu yapın. Türetilmiş değerler bileşen gövdesinde (component body) veya useMemo ile memoize edilmiş bir hesaplamada yer almalıdır. Bunları bir effect içine taşımak, mantığınızı hiçbir fayda sağlamadan render ve effect aşamaları arasında böler ve kodun takibini zorlaştırır.

Kullanıcı eylemleri için yanlış araç. `use