- Konu sahibi
- #1
React’te
Bir effect’in çalışması şu zinciri izleyebilir:
Önemli ayrım şudur: Bir effect’in her render’dan sonra çalışması tek başına sonsuz döngü değildir. Sonsuz döngü için genellikle effect’in render’ı tetikleyen bir güncelleme yapması ve bu güncellemenin effect’in tekrar çalışmasına yol açması gerekir.
Aşağıdaki component her effect çalıştığında
Burada beklenen başarı çıktısı oluşmaz; tarayıcı sürekli render etmeye çalışır ve uygulama hata verebilir veya tarayıcı yanıt vermemeye başlayabilir. Sorun,
Önce effect’in gerçekten gerekli olup olmadığını belirleyin. Bir değeri yalnızca başka props veya state değerlerinden hesaplıyorsanız bunu effect ile state’e yazmak yerine doğrudan render sırasında hesaplayın:
Bu örnekte
Effect gerçekten bir dış sistemle senkronizasyon için gerekiyorsa okuduğu reactive değerlerin tamamını bağımlılık listesinde belirtin. Ardından döngüye neden olan gereksiz state’i, koşulsuz yazmayı veya her render’da oluşan bağımlılığı yeniden tasarlayın. State yalnızca önceki değerini artırmak için okunuyorsa fonksiyonel updater bazı durumlarda o okumayı kaldırabilir; diğer gerekli bağımlılıkları kaldırma gerekçesi değildir. Tek seferlik ilk kurulum gerekiyorsa boş bağımlılık listesi kullanılabilir; ancak effect’in kullandığı değişkenler sonradan değişebiliyorsa bu yaklaşım eski değer kullanma sorununa yol açabilir.
Aşağıdaki tablo, döngünün kaynağını bulmayı kolaylaştırır:
React her bağımlılık için
Geliştirme ortamında Strict Mode kullanılması effect’in kurulum ve temizleme davranışını denetlemek için ek çalıştırmalar gösterebilir. Bu durum tek başına sonsuz döngü anlamına gelmez. Ancak effect cleanup yapmıyor veya her çalışmada koşulsuz state güncelliyorsa bu denetim gerçek tasarım sorununu görünür hâle getirebilir.
Hayır. Effect içinde state güncelleniyorsa bağımlılık dizisi olmasa da effect her render’dan sonra çalışabilir ve aynı döngüyü sürdürebilir. Önce gereksiz state güncellemesini kaldırmak gerekir.
Genellikle hayır. Strict Mode geliştirme sırasında effect’in hatalı cleanup veya tekrar çalıştırılma davranışlarını görünür kılar. Sürekli render’ın asıl nedeni çoğunlukla effect ile state arasında kurulmuş geri besleme döngüsüdür.
useEffect sonsuz döngüsü, effect içinde bir state güncellenmesiyle yeni render oluşması, bu render sonrasında effect’in bağımlılıklarının değişmiş kabul edilmesi ve effect’in aynı state’i tekrar güncellemesi nedeniyle oluşur. Sorun bağımlılığı listelemek değil, effect’in kendi yeniden çalışmasını sürekli tetikleyen güncelleme tasarımıdır. Effect içinde okunan reactive değerleri listeden silerek hatayı gizlemeyin. Her render’da yeniden oluşan nesne veya fonksiyonlar da bu döngüyü sürdürebilir.Döngü nasıl oluşur?
Bir effect’in çalışması şu zinciri izleyebilir:
- Component render edilir.
- React, bağımlılıkları değişmişse effect’i çalıştırır.
- Effect
setStateçağırır. - State değiştiği için component yeniden render edilir.
- Yeni render’da effect’in bağımlılığı değişmiş görünür.
- Effect tekrar çalışır ve döngü yeniden başlar.
Önemli ayrım şudur: Bir effect’in her render’dan sonra çalışması tek başına sonsuz döngü değildir. Sonsuz döngü için genellikle effect’in render’ı tetikleyen bir güncelleme yapması ve bu güncellemenin effect’in tekrar çalışmasına yol açması gerekir.
En basit hatalı örnek
Aşağıdaki component her effect çalıştığında
count değerini artırır. Effect count değerini izlediği için her artış yeni bir effect çalıştırır:
JavaScript:
import { useEffect, useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1);
}, [count]);
return <p>Değer: {count}</p>;
}
Burada beklenen başarı çıktısı oluşmaz; tarayıcı sürekli render etmeye çalışır ve uygulama hata verebilir veya tarayıcı yanıt vermemeye başlayabilir. Sorun,
setCount çağrısının count değişikliğini tetiklemesi, count değişikliğinin de effect’i yeniden çalıştırmasıdır.Doğru çözümü seçme
Önce effect’in gerçekten gerekli olup olmadığını belirleyin. Bir değeri yalnızca başka props veya state değerlerinden hesaplıyorsanız bunu effect ile state’e yazmak yerine doğrudan render sırasında hesaplayın:
JavaScript:
import { useState } from "react";
export default function Price({ quantity, unitPrice }) {
const [discount, setDiscount] = useState(0);
const total = quantity * unitPrice - discount;
return (
<section>
<label>İndirim
<input
type="number"
value={discount}
onChange={(event) => setDiscount(Number(event.target.value))}
/>
</label>
<p>Toplam: {total}</p>
</section>
);
}
Bu örnekte
total için effect gerekmez; quantity, unitPrice veya discount değiştiğinde değer yeniden hesaplanır.Effect gerçekten bir dış sistemle senkronizasyon için gerekiyorsa okuduğu reactive değerlerin tamamını bağımlılık listesinde belirtin. Ardından döngüye neden olan gereksiz state’i, koşulsuz yazmayı veya her render’da oluşan bağımlılığı yeniden tasarlayın. State yalnızca önceki değerini artırmak için okunuyorsa fonksiyonel updater bazı durumlarda o okumayı kaldırabilir; diğer gerekli bağımlılıkları kaldırma gerekçesi değildir. Tek seferlik ilk kurulum gerekiyorsa boş bağımlılık listesi kullanılabilir; ancak effect’in kullandığı değişkenler sonradan değişebiliyorsa bu yaklaşım eski değer kullanma sorununa yol açabilir.
Yaygın nedenleri ayırt etme
Aşağıdaki tablo, döngünün kaynağını bulmayı kolaylaştırır:
| Neden | Belirti | Uygun yaklaşım |
|---|---|---|
| Effect içinde sürekli state güncellemek | Her çalışmada yeni değer yazılır | Hesabı render sırasında yapın veya güncellemeyi koşula bağlayın |
| Yeni nesne veya dizi bağımlılığı | İçerik aynı olsa da referans değişir | Bağımlılıkları temel değerlere ayırın veya gerektiğinde useMemo kullanın |
| Yeni fonksiyon bağımlılığı | Her render’da fonksiyon yeniden oluşturulur | Fonksiyonu effect içine taşıyın veya gerçekten gerekiyorsa useCallback kullanın |
| Koşulsuz veri senkronizasyonu | Effect’in yazdığı state tekrar tetikleyici olur | Yalnızca değişiklik olduğunda güncelleyin; mümkünse türetilmiş state kullanmayın |
React her bağımlılık için
Object.is karşılaştırması yapar; nesnelerde derin içerik eşitliği aramaz. Bu nedenle { id: 1 } gibi bir nesne her render’da yeniden oluşturuluyorsa içerik aynı olsa bile yeni referans sayılır. Benzer şekilde satır içi fonksiyonlar da her render’da yeni bir referans oluşturabilir.Teşhis ve düzeltme adımları
- Effect içindeki tüm
setStateçağrılarını bulun ve bu güncellemenin gerçekten gerekli olup olmadığını sorun. - Effect’in bağımlılıklarını tek tek inceleyin. Değişen bağımlılığın primitive değer mi, yoksa her render’da oluşturulan nesne, dizi veya fonksiyon mu olduğunu kontrol edin.
- Effect yalnızca bir hesap yapıyorsa state’i kaldırıp sonucu render sırasında hesaplayın.
- Dış sistemle senkronizasyon yapıyorsanız güncellemenin bir koşula bağlı olduğundan emin olun.
- Gerekli düzeltmeden sonra effect’in beklenen sayıda çalıştığını ve cleanup işlevinin eski abonelikleri temizlediğini kontrol edin.
Geliştirme ortamında Strict Mode kullanılması effect’in kurulum ve temizleme davranışını denetlemek için ek çalıştırmalar gösterebilir. Bu durum tek başına sonsuz döngü anlamına gelmez. Ancak effect cleanup yapmıyor veya her çalışmada koşulsuz state güncelliyorsa bu denetim gerçek tasarım sorununu görünür hâle getirebilir.
Kaynaklar
Sık sorulan sorular
Bağımlılık dizisini tamamen kaldırmak sonsuz döngüyü çözer mi?
Hayır. Effect içinde state güncelleniyorsa bağımlılık dizisi olmasa da effect her render’dan sonra çalışabilir ve aynı döngüyü sürdürebilir. Önce gereksiz state güncellemesini kaldırmak gerekir.
Strict Mode sonsuz döngünün nedeni midir?
Genellikle hayır. Strict Mode geliştirme sırasında effect’in hatalı cleanup veya tekrar çalıştırılma davranışlarını görünür kılar. Sürekli render’ın asıl nedeni çoğunlukla effect ile state arasında kurulmuş geri besleme döngüsüdür.