USEEFFECT KAYNAKLI HATALARI ÖNLEMEK VE BAĞIMLILIK YÖNETMEK
React’te işler “çalışıyor gibi” göründüğü halde üretimde garip bug’ların çıkmasının en yaygın sebeplerinden biri useEffect kullanımındaki küçük hatalardır. Bir kere fazla çalışan bir effect, yanlış bağımlılık listesi veya unutulmuş cleanup; API’yi gereksiz yorar, UI’ı tutarsızlaştırır ve hata ayıklamayı uzatır.
useEffect, “yan etki” (side effect) yönetmek için güçlü bir araçtır; fakat gücü kadar risk de taşır. Bu yazıda, bağımlılık mantığını doğru kurmayı, stale closure kaynaklı hataları görmeyi, veri çekme ve abonelik senaryolarında güvenli kalıplar kurmayı ele alacağız.
Bu konuyu pratikle pekiştirmek ve ekip içinde ortak kod standardı oluşturmak için react eğitimi içeriğini de inceleyebilirsiniz.

useEffect amacını netleştirmek ve sınır koymak
useEffect, render sonucu oluşan UI’a “dış dünya” ile etkileşim eklemek içindir: veri çekmek, abonelik kurmak, DOM ölçmek, event listener bağlamak gibi. Ancak pek çok projede useEffect, state’i state ile güncellemek için kullanılır ve bu da sonsuz döngü riskini artırır.
Yan etkiyi tanımlamak ve gereksiz effect yazmamak
Bir işlem sadece state hesaplamaksa, effect yerine render sırasında hesaplama veya memoization tercih edilmelidir. “State’i güncelleyeyim, sonra bir şey daha güncelleyeyim” yaklaşımı çoğu zaman gereksiz karmaşa üretir.
Effect’i küçük tutmak ve tek sorumluluk taşımak
Aynı effect içinde hem veri çekip hem analytics tetiklemek hem de local storage yazmak, bağımlılık listesini karmaşıklaştırır. Etkileri bölmek, bağımlılık yönetimini sadeleştirir ve hata ayıklamayı hızlandırır.
Bağımlılık listesini doğru kurmak ve tutarlı hale getirmek
useEffect’in ikinci parametresi, effect’in ne zaman çalışacağını belirleyen bağımlılıklardır. Bu liste eksik olursa stale değerler kullanılır; fazla olursa gereksiz tekrarlar oluşur. Hedef, effect içinde kullanılan reaktif değerlerin (props, state, fonksiyon referansları) listeye doğru şekilde girmesidir.
Stale closure riskini fark etmek ve önlemek
Effect içinde okunan bir state değeri dependency’ye eklenmezse, effect eski değeri “hatırlar”. Bu durum, özellikle interval/timeout veya event handler bağlama senaryolarında sık görülür. Çözüm; doğru dependency, functional update veya ref kullanımı olabilir.
Fonksiyon bağımlılıklarını yönetmek ve referansı sabitlemek
Effect içinde kullanılan fonksiyonlar her render’da yeniden oluşuyorsa, effect sürekli tetiklenebilir. Bu tip durumlarda useCallback ile referansı stabilize etmek veya effect içindeki akışı yeniden tasarlamak gerekir. Amaç, bağımlılık listesini “susturmak” değil, davranışı doğru kurmaktır.
import React, { useCallback, useEffect, useState } from "react";
export default function SearchBox({ api }) {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const fetchResults = useCallback(async (q) => {
const data = await api.search(q);
setResults(data);
}, [api]);
useEffect(() => {
if (!query.trim()) {
setResults([]);
return;
}
fetchResults(query);
}, [query, fetchResults]);
return (
<div>
<input value={query} onChange={(e) => setQuery(e.target.value)} />
<div>Sonuç: {results.length}</div>
</div>
);
}Cleanup mantığını uygulamak ve sızıntıları engellemek
Effect içinde abonelik, listener, timer veya async süreç başlatıyorsanız, cleanup ile bunları durdurmanız gerekir. Aksi halde “unmounted component” güncellemeleri, memory leak benzeri sorunlar ve beklenmedik UI davranışları görülebilir.
Event listener ve abonelikleri temizlemek ve kontrol etmek
window event’leri, WebSocket abonelikleri veya custom emitter kullanımı; cleanup gerektirir. Cleanup, sadece unmount’ta değil, dependency değiştiğinde de önceki bağlantıyı kapatmak için çalışır.
Timer ve interval kullanımını güvenli yönetmek ve azaltmak
setInterval ile state okurken stale closure sık görülür. Çözüm olarak functional update kullanmak veya ref ile güncel değeri tutmak tercih edilebilir. Ayrıca interval ihtiyacı yoksa event bazlı model daha doğru olabilir.
import React, { useEffect, useState } from "react";
export default function PollingCounter() {
const [count, setCount] = useState(0);
useEffect(() => {
const id = setInterval(() => {
setCount((c) => c + 1); // stale closure yerine functional update
}, 1000);
return () => clearInterval(id);
}, []);
return <div>Sayaç: {count}</div>;
}Veri çekme akışını kurgulamak ve yarış koşullarını önlemek
useEffect içinde fetch yapmak doğaldır; fakat hızlı değişen query/state ile birden fazla istek üst üste binebilir. Eski istek geç dönerse yeni sonucu ezebilir. Bu “race condition” problemi, özellikle arama kutusu ve filtre akışlarında çok yaygındır.
AbortController ile istek iptal etmek ve güncel sonucu korumak
Tarayıcı fetch API’si AbortController destekler. Dependency değiştiğinde önceki isteği iptal etmek, gereksiz ağ trafiğini azaltır ve UI’ın eski veriyle güncellenmesini engeller. API katmanı farklıysa benzer iptal mekanizmaları (cancel token) kullanılabilir.
Debounce yaklaşımını doğru konumlandırmak ve etkisini ölçmek
Arama gibi akışlarda debounce hem performansı hem de kullanıcı deneyimini iyileştirir. Debounce’u input onChange içinde değil, effect akışında veya özel hook içinde yönetmek daha izlenebilir bir yapı sağlar.
Pratik kontrol listesi oluşturmak ve ekip standardı koymak
useEffect hataları çoğu zaman küçük detaylardan çıkar. Bu yüzden ortak bir kontrol listesi, kod incelemede hız kazandırır. Aşağıdaki maddeler, hatayı erken yakalamaya yardımcı olur.
- Effect gerçekten gerekli mi? Sadece hesaplama ise effect yazmamak
- Dependency listesi tam mı? İçeride kullanılan reaktif değerleri eklemek
- Cleanup var mı? Listener, abonelik, timer ve async süreçleri temizlemek
- Race condition var mı? İptal/guard mekanizması eklemek
- Effect tek sorumluluk mu? Büyük effect’leri bölmek
Lint kurallarını kullanmak ve istisnaları gerekçelendirmek
eslint-plugin-react-hooks gibi kurallar, dependency hatalarını erken gösterir. Kurala rağmen bağımlılığı bilerek dışarıda bırakıyorsanız, bunun teknik gerekçesini net yazmak gerekir. “Susturmak için ignore” yaklaşımı, ileride üretim hatasına dönüşebilir.
Custom hook ile tekrar eden kalıpları soyutlamak ve paylaşmak
Debounced search, safe fetch, subscription yönetimi gibi tekrar eden effect kalıpları custom hook ile toparlanabilir. Bu sayede ekip, aynı problemi farklı farklı çözmek yerine ortak bir yaklaşım üzerinden ilerler. Daha fazla örnek ve pratik için react eğitimi sayfası faydalı olacaktır.

Kapanış: useEffect kaynaklı hataları azaltmanın yolu; effect amacını netleştirmek, bağımlılık listesini doğru kurmak, cleanup ile sızıntıları engellemek ve veri çekme akışında yarış koşullarını kontrol etmektir. Bu adımlar, hem performansı hem de hata ayıklama hızını belirgin şekilde iyileştirir.


