Geliştirme ortamında useEffect neden iki kez çalışıyor? Bu bir hata mı?
Cevap
Hata değil. React 18+ ile <StrictMode> açıkken, sadece development ortamında React her bileşeni mount ettikten hemen sonra efektleri bir kez temizleyip (cleanup) tekrar çalıştırır: mount -> unmount -> mount. Amaç, cleanup'ı eksik olan efektleri erkenden yakalamaktır. Production'da efekt bir kez çalışır.
Neden böyle?
Gelecekteki özellikler (ör. <Activity> ile ekran dışına alınan bileşenlerin state'i korunarak geri getirilmesi, Fast Refresh) bileşenlerin birden fazla kez mount/unmount olabilmesini gerektirir. Efektiniz buna dayanıklı değilse StrictMode bunu görünür kılar.
Doğru yaklaşım: düzgün cleanup yazmak
useEffect(() => {
const controller = new AbortController();
fetch(`/api/users/${id}`, { signal: controller.signal })
.then((r) => r.json())
.then(setUser)
.catch((e) => { if (e.name !== "AbortError") setError(e); });
return () => controller.abort();
}, [id]);
useEffect(() => {
const conn = createConnection(roomId);
conn.connect();
return () => conn.disconnect();
}, [roomId]);Yanlış çözümler
StrictMode'u kaldırmak: sorunu gizler.useRefile "zaten çalıştı" bayrağı tutmak: genelde asıl sorunu (eksik cleanup) çözmez.
İstisna
Analytics "sayfa görüntülendi" gibi gerçekten bir kez olması gereken işlemler dev'de iki kez görünür; bu kabul edilebilir. Satın alma gibi kullanıcı aksiyonları zaten efektte değil event handler'da olmalıdır.
İlgili React soruları
- Virtual DOM nedir ve reconciliation nasıl çalışır?
- Listelerde key prop neden önemlidir? Index kullanmak neden sorunludur?
- Controlled ve uncontrolled component farkı nedir?
- useEffect bağımlılık dizisi nasıl çalışır?
- useMemo ile useCallback arasındaki fark nedir?
- Gereksiz render'ları nasıl tespit eder ve önlersiniz?
Bu konuda başka bir soru biliyor musun?
Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.