React uygulamalarında bileşenlerimizin yalnızca arayüzü değil, aynı zamanda dış dünya ile etkileşimini de yönetmemiz gerekir. Peki, bu yan etkileri (side effects) düzenli ve performanslı bir şekilde nasıl ele alabiliriz? İşte tam da bu noktada, React’ın güçlü ve esnek Hook’u olan useEffect devreye giriyor ve bileşenlerinizin yaşam döngüsünü daha fonksiyonel bir bakış açısıyla yönetmenizi sağlıyor.
Modern web uygulamaları, sadece statik içerik göstermekle kalmaz, aynı zamanda API’lerden veri çeker, kullanıcı etkileşimlerine tepki verir, animasyonları yönetir ve tarayıcı API’leri (localStorage, navigator gibi) ile iletişim kurar. React dünyasında, bir bileşenin render edilmesi sırasında doğrudan gerçekleşmeyen, yani “saf” fonksiyonel olmayan tüm bu işlemlere yan etki (side effect) diyoruz. Örneğin, bir sunucudan veri çekmek, bir olay dinleyicisi (event listener) eklemek, manuel olarak DOM’u manipüle etmek veya bir zamanlayıcı (timer) ayarlamak tipik yan etkilerdir.
useEffect Hook’u, fonksiyonel bileşenlerimizde bu yan etkileri bildirimsel bir şekilde belirtmemize olanak tanır. React, bileşen render edildikten sonra (veya belirli bağımlılıklar değiştiğinde) bu yan etkileri çalıştırır. Temel olarak, useEffect bize “Bu işi, bileşenim ekrana yerleştikten veya şu değerler değiştikten sonra yap” deme gücü verir. Class bileşenlerindeki componentDidMount, componentDidUpdate ve componentWillUnmount yaşam döngüsü metodlarının birleşimini modern ve daha anlaşılır bir yapıda sunar. Bu sayede kod tekrarını azaltır, ilgili mantığı tek bir yerde toplar ve bileşenlerimizin daha okunabilir olmasını sağlar.
useEffect‘in çalışma prensibini anlamak için temel sözdizimine bakmak önemlidir:
import React, { useEffect, useState } from 'react'; function VeriCekmeBileseni() { const [veri, setVeri] = useState(null); const [yukleniyor, setYukleniyor] = useState(true); const [hata, setHata] = useState(null); useEffect(() => { // Bu fonksiyon, bileşen render edildikten sonra çalışır. const fetchData = async () => { try { const response = await fetch('https://api.example.com/data'); if (!response.ok) { throw new Error(HTTP hatası! Durum: ${response.status}); } const result = await response.json(); setVeri(result); } catch (error) { setHata(error); } finally { setYukleniyor(false); } }; fetchData(); // Veri çekme işlemini başlat // İsteğe bağlı temizleme fonksiyonu: // Bu fonksiyon, bileşen unmount edildiğinde veya bağımlılıklar değişmeden önce çalışır. return () => { // Örneğin, devam eden bir isteği iptal etme veya olay dinleyicilerini kaldırma. console.log('Veri çekme efekti temizlendi.'); }; }, []); // Bağımlılık dizisi boş olduğu için sadece ilk render'da çalışır. if (yukleniyor) returnYükleniyor...; if (hata) returnHata: {hata.message}; return (Çekilen Veri:
{JSON.stringify(veri, null, 2)});
}
Yukarıdaki örnekte,
useEffectbir API'den veri çekme işlemini yönetiyor. Boş bağımlılık dizisi[], bu efektin yalnızca bileşen ilk kez DOM'a eklendiğinde (mount edildiğinde) bir kez çalışmasını sağlar. Bu sayede, her yeniden render işleminde gereksiz veri çekme isteklerinin önüne geçilir, böylece ağ yükü ve performans artırılmış olur.useEffect'in döndürdüğü opsiyonel temizleme fonksiyonu ise, bileşen unmount edildiğinde veya efekt yeniden çalışmadan önce kaynakların düzgün bir şekilde serbest bırakılmasını sağlayarak bellek sızıntılarını önler. Bu dauseEffect'in sadece işleri başlatmakla kalmayıp, aynı zamanda sonlandırmak için de ne kadar önemli olduğunu gösterir.Bağımlılık Dizisi (Dependency Array) Nasıl Çalışır ve Hatalar Nasıl Önlenir?
useEffectHook'unun en kritik ve belki de en çok yanlış anlaşılan parçalarından biri bağımlılık dizisidir. Bu dizi, React'a "Bu efekti ne zaman yeniden çalıştırmalıyım?" sorusunun cevabını verir. Bağımlılık dizisi (ikinci argüman),useEffect'in içindeki callback fonksiyonunun hangi değerlere bağımlı olduğunu belirtir. React, bu dizideki değerlerden herhangi birinin bir önceki render'dan farklı olup olmadığını kontrol eder. Eğer farklıysa, efekt callback'ini yeniden çalıştırır.
- Boş Dizi (
[]): Efekt, bileşen ilk monte edildiğinde (mount) bir kez çalışır ve bir daha asla çalışmaz (temizleme fonksiyonu hariç). Bu,componentDidMountdavranışına benzer. Örneğin, başlangıç verilerini çekmek veya olay dinleyicilerini bir kez ayarlamak için idealdir. - Dizi Yok (argüman verilmemiş): Efekt, bileşen her render edildiğinde çalışır. Bu genellikle istenmeyen bir durumdur ve performans sorunlarına yol açabilir, çünkü her state veya prop değiştiğinde yan etki yeniden tetiklenir.
- Dolu Dizi (
[dep1, dep2]): Efekt, bileşen ilk monte edildiğinde çalışır ve daha sonra yalnızcadep1veyadep2değerlerinden herhangi biri değiştiğinde yeniden çalışır. Bu,componentDidUpdate'in belirli koşullar altında çalışmasına benzer bir kontrol sağlar.
Vaka Analizi: Kullanıcı ID'sine Göre Veri Çekme
Bir kullanıcı profil sayfasında, URL'den alınan userId prop'una göre kullanıcı verilerini çekmemiz gerektiğini düşünelim. Kullanıcı ID'si değiştiğinde verilerin güncellenmesi gerekir.
import React, { useEffect, useState } from 'react';
function KullaniciProfilBileseni({ userId }) {
const [kullaniciVerisi, setKullaniciVerisi] = useState(null);
const [yukleniyor, setYukleniyor] = useState(true);
useEffect(() => {
setYukleniyor(true); // Yeni veri çekilirken yüklenme durumunu ayarla
const fetchKullanici = async () => {
try {
const response = await fetch(https://api.example.com/users/${userId});
const data = await response.json();
setKullaniciVerisi(data);
} catch (error) {
console.error('Kullanıcı verisi çekilirken hata oluştu:', error);
} finally {
setYukleniyor(false);
}
};
fetchKullanici();
// Temizleme fonksiyonu (isteğe bağlı, burada gerekli değilse de iyi bir pratiktir)
return () => {
// Örneğin, devam eden bir isteği iptal etmek için kullanılabilir.
console.log(Kullanıcı ID ${userId} için efekt temizlendi.);
};
}, [userId]); // userId değiştiğinde efekti yeniden çalıştır.
if (yukleniyor) return Kullanıcı bilgileri yükleniyor...;
if (!kullaniciVerisi) return Kullanıcı bulunamadı.;
return (
Kullanıcı Profili
Ad: {kullaniciVerisi.name}
Email: {kullaniciVerisi.email}
);
}
Bu örnekte, bağımlılık dizisindeki [userId], React'a userId prop'u her değiştiğinde efekti yeniden çalıştırması gerektiğini söyler. Eğer userId değişmezse, bileşen yeniden render olsa bile efekt yeniden çalışmaz, bu da gereksiz ağ isteklerini önler. Ancak, bağımlılıkları doğru bir şekilde belirtmek çok önemlidir. Eğer userId'yi bağımlılık dizisinden çıkarırsanız, efekt sadece bileşen ilk monte edildiğinde çalışır ve userId daha sonra değişse bile yeni verileri çekmez. Bu "stale closure" (eskimiş kapanış) sorununa yol açabilir, yani efektin içinde kullanılan userId değeri ilk render'daki değer olarak kalır.
useCallback veya useMemo ile sarmalanmamışsa) bağımlılık olarak eklemeyi unutmayın. eslint-plugin-react-hooks'un exhaustive-deps kuralı bu konuda size büyük ölçüde yardımcı olacaktır.
Ayrıca, bağımlılık dizisine nesne veya dizi gibi referans tiplerini doğrudan eklerken dikkatli olmalısınız. JavaScript'te nesneler ve diziler referansla karşılaştırılır, bu da her render'da yeni bir nesne veya dizi oluşturulduğunda, içeriği aynı olsa bile useEffect'in yeniden çalışmasına neden olabilir. Bu durumu önlemek için, bu tür değerleri useMemo ile sarmalayarak referans stabilitesini sağlayabilirsiniz.
Temizleme Fonksiyonu (Cleanup Function) Nedir ve Neden Önemlidir?
useEffect sadece yan etkileri başlatmakla kalmaz, aynı zamanda onları düzgün bir şekilde sonlandırmamıza da olanak tanır. İşte bu noktada, useEffect callback'inden döndürülen temizleme fonksiyonu (cleanup function) devreye girer. Bu fonksiyon, bileşen DOM'dan kaldırılmadan (unmount) önce veya bir sonraki render'da efekt yeniden çalışmadan önce tetiklenir.
Temizleme fonksiyonunun temel amacı, bellek sızıntılarını önlemek ve gereksiz kaynak tüketimini durdurmaktır. React, bir efektin bir önceki çalışmasından kaynaklanan herhangi bir aboneliği, olay dinleyicisini veya zamanlayıcıyı kaldırmak için bu fonksiyonu kullanır. Bu mekanizma, uygulamanızın uzun vadeli kararlılığı ve performansı için hayati öneme sahiptir.
Vaka Analizi: Pencere Yeniden Boyutlandırma Dinleyicisi Yönetimi
Bir bileşenin, pencerenin boyutunu her değiştiğinde takip etmesi gerektiğini ve bu bilgiyi kullanarak arayüzünü güncellemesi gerektiğini düşünelim.
import React, { useEffect, useState } from 'react';
function PencereBoyutuGosterici() {
const [boyut, setBoyut] = useState({
genislik: window.innerWidth,
yukseklik: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
setBoyut({
genislik: window.innerWidth,
yukseklik: window.innerHeight,
});
};
window.addEventListener('resize', handleResize); // Olay dinleyicisini ekle
// Temizleme fonksiyonu:
return () => {
window.removeEventListener('resize', handleResize); // Bileşen unmount edildiğinde kaldır
console.log('Pencere boyutu dinleyicisi kaldırıldı.');
};
}, []); // Sadece bileşen ilk monte edildiğinde bir kez ayarla
return (
Pencere Boyutu
Genişlik: {boyut.genislik}px
Yükseklik: {boyut.yukseklik}px
);
}
Bu örnekte, useEffect ile bir 'resize' olay dinleyicisi ekleniyor. Eğer temizleme fonksiyonunu sağlamazsak ve bileşen DOM'dan kaldırılırsa, handleResize fonksiyonu hala çalışmaya devam ederdi. Bu, kaldırılmış bir bileşenin state'ini güncellemeye çalışarak hatalara yol açabilir ve potansiyel olarak uygulamanızda performans sorunlarına neden olabilir. Temizleme fonksiyonu (return () => { ... }), bileşen unmount edildiğinde veya bağımlılıklar (bu örnekte boş dizi olduğu için sadece unmount durumunda) değiştiğinde dinleyiciyi kaldırır. Bu, uygulamanın daha kararlı ve verimli çalışmasını sağlar.
Temizleme fonksiyonu ayrıca, bir useEffect içinde başlatılan aboneliklerin (WebSockets gibi), zamanlayıcıların (setTimeout, setInterval) veya diğer uzun ömürlü işlemlerin iptal edilmesi için de kullanılır. Herhangi bir harici kaynağa bağlandığınızda veya küresel bir şeye müdahale ettiğinizde, genellikle bir temizleme fonksiyonuna ihtiyacınız vardır. Bu, React'ın tek yönlü veri akışını ve bileşen izolasyonunu korumanın önemli bir parçasıdır.
function ZamanlayiciBileseni() {
const [saniye, setSaniye] = useState(0);
useEffect(() => {
const intervalId = setInterval(() => {
setSaniye(prevSaniye => prevSaniye + 1);
}, 1000);
// Zamanlayıcıyı temizle
return () => {
clearInterval(intervalId);
console.log('Zamanlayıcı durduruldu.');
};
}, []); // Sadece ilk render'da başla
return Geçen Süre: {saniye} saniye
;
}
Yukarıdaki kodda, clearInterval(intervalId) çağrısı, bileşen ekrandan kaldırıldığında zamanlayıcının çalışmasını durdurur. Aksi takdirde, bileşen olmasa bile her saniye state güncellemesi yapmaya çalışarak hata ve performans sorunlarına yol açardı. Bu nedenle, useEffect kullanırken temizleme fonksiyonunu düşünmek, sağlam ve hatasız uygulamalar yazmak için kritik bir adımdır.
Performans Optimizasyonu: useEffect ile Gereksiz Yeniden Çalışmaları Önleme
useEffect doğru kullanılmadığında, React uygulamanızda ciddi performans düşüşlerine neden olabilir. Özellikle bağımlılık dizisini yanlış belirlemek veya hiç belirtmemek, efektin her render'da gereksiz yere çalışmasına yol açar. Bu da sık sık ağ istekleri göndermeye, ağır hesaplamalar yapmaya veya DOM'u gereksiz yere manipüle etmeye neden olabilir.
Performansı optimize etmek için, useEffect'in yalnızca gerçekten ihtiyaç duyulduğunda çalışmasını sağlamak esastır. Bunun için en önemli araç, elbette bağımlılık dizisidir. Ancak bazen bağımlılık dizisine eklemeniz gereken bir fonksiyon veya nesne, her render'da yeniden oluşturulduğu için efekti gereksiz yere tetikleyebilir. İşte bu noktada useCallback ve useMemo Hook'ları devreye girer.
useCallback: Bir fonksiyonun referansını hafızaya (memoize) alır. Eğer bir fonksiyonuuseEffect'in bağımlılık dizisine eklemeniz gerekiyorsa ve bu fonksiyon prop olarak alt bileşenlere geçiriliyorsa,useCallbackkullanarak bu fonksiyonun referansının her render'da değişmesini engelleyebilirsiniz. Bu, hemuseEffect'in gereksiz çalışmasını önler hem de alt bileşenlerin gereksiz yeniden render edilmesini engeller.useMemo: Bir değerin (nesne, dizi veya karmaşık hesaplama sonucu) referansını hafızaya alır. EğeruseEffectiçinde veya bağımlılık dizisinde kullanılan bir nesne veya dizi, her render'da yeni bir referansla oluşturuluyorsa,useMemokullanarak bu referansın stabil kalmasını sağlayabilirsiniz.
Vaka Analizi: Performanslı Arama Filtresi
Bir ürün listesi uygulaması düşünün. Kullanıcı bir arama terimi girdiğinde, sunucudan filtrelenmiş verileri çekmemiz gerekiyor. Ancak her tuş vuruşunda istek göndermek yerine, kullanıcının yazmayı bitirmesini beklemeliyiz (debounce).
import React, { useEffect, useState, useMemo } from 'react';
function UrunArama({ aramaTerimi }) {
const [urunler, setUrunler] = useState([]);
const [yukleniyor, setYukleniyor] = useState(false);
const [debouncedAramaTerimi, setDebouncedAramaTerimi] = useState(aramaTerimi);
// aramaTerimi değiştiğinde debouncedAramaTerimi'ni güncelle
// Kullanıcının yazmayı bitirmesini bekler
useEffect(() => {
setYukleniyor(true);
const handler = setTimeout(() => {
setDebouncedAramaTerimi(aramaTerimi);
}, 500); // 500ms bekle
return () => {
clearTimeout(handler); // Zamanlayıcıyı temizle
};
}, [aramaTerimi]); // aramaTerimi her değiştiğinde bu efekti çalıştır
// Debounced arama terimi değiştiğinde API'den veri çek
useEffect(() => {
if (!debouncedAramaTerimi) {
setUrunler([]); // Arama terimi yoksa boşalt
setYukleniyor(false);
return;
}
const fetchUrunler = async () => {
try {
const response = await fetch(https://api.example.com/products?q=${debouncedAramaTerimi});
const data = await response.json();
setUrunler(data);
} catch (error) {
console.error('Ürünler çekilirken hata oluştu:', error);
} finally {
setYukleniyor(false);
}
};
fetchUrunler();
}, [debouncedAramaTerimi]); // Yalnızca debouncedAramaTerimi değiştiğinde çalışır
return (
Ürün Arama Sonuçları ({aramaTerimi})
{yukleniyor && Ürünler aranıyor...
}
{urunler.map(urun => (
- {urun.name}
))}
);
}
Bu örnekte iki ayrı useEffect kullanılmıştır. İlk useEffect, aramaTerimi prop'u her değiştiğinde bir gecikme (debounce) uygular ve bu sayede debouncedAramaTerimi state'ini sadece kullanıcı yazmayı bıraktığında günceller. İkinci useEffect ise, yalnızca debouncedAramaTerimi değiştiğinde API isteğini gönderir. Bu yaklaşım, gereksiz API isteklerini büyük ölçüde azaltarak hem sunucu yükünü hafifletir hem de kullanıcı arayüzü deneyimini iyileştirir.
useEffect içinde karmaşık ve pahalı hesaplamalar yapıyorsanız, bu hesaplamaların sonucunu useMemo ile önbelleğe almayı düşünebilirsiniz. Bu, efektin içindeki mantığın her çalışmasında aynı hesaplamayı tekrarlamasını önler, böylece özellikle büyük veri setleriyle çalışırken performans artışı sağlar.
Ayrıca, bazen farklı yan etkileri tek bir useEffect içinde birleştirmek yerine, ilgili yan etkileri mantıksal olarak ayrı useEffect bloklarına bölmek daha iyi bir stratejidir. Bu, her bir yan etkinin kendi bağımlılıklarına sahip olmasını sağlar ve tek bir büyük efektten kaynaklanabilecek gereksiz yeniden çalışmaları önler. Kodun okunabilirliğini ve bakımını da kolaylaştırır. Örneğin, bir API'den veri çekmek için bir useEffect ve bir olay dinleyicisi eklemek için başka bir useEffect kullanmak daha doğru bir yaklaşımdır.
İleri Düzey Senaryolar: useEffect ile Asenkron İşlemler ve Veri Senkronizasyonu
useEffect Hook'u, sadece basit yan etkileri yönetmekle kalmaz, aynı zamanda asenkron veri akışlarını ve karmaşık senkronizasyon senaryolarını da güçlü bir şekilde ele alabilir. Modern uygulamalarda sıkça karşılaştığımız API çağrıları, WebSocket abonelikleri veya zamanlanmış görevler gibi asenkron işlemler, useEffect ile güvenli ve etkin bir şekilde yönetilebilir.
Ancak, useEffect'in callback fonksiyonu doğrudan bir async fonksiyon olamaz. Çünkü async fonksiyonlar her zaman bir Promise döndürür ve useEffect'ten bir Promise döndürmek, React'ın beklediği bir temizleme fonksiyonu değil, farklı bir davranıştır. Bu durumu çözmek için, useEffect içinde asenkron bir fonksiyon tanımlayıp onu hemen çağırmak yaygın bir desendir:
import React, { useEffect, useState } from 'react';
function AsyncVeriCekme({ id }) {
const [veri, setVeri] = useState(null);
const [yukleniyor, setYukleniyor] = useState(true);
useEffect(() => {
let isCancelled = false; // Bellek sızıntılarını önlemek için flag
const fetchVeri = async () => {
setYukleniyor(true);
try {
const response = await fetch(https://api.example.com/items/${id});
const result = await response.json();
if (!isCancelled) { // Bileşen unmount edilmediyse state'i güncelle
setVeri(result);
}
} catch (error) {
if (!isCancelled) {
console.error("Veri çekme hatası:", error);
}
} finally {
if (!isCancelled) {
setYukleniyor(false);
}
}
};
fetchVeri();
// Temizleme fonksiyonu:
return () => {
isCancelled = true; // Bileşen unmount edildiğinde veya id değiştiğinde isteği iptal et
console.log(Asenkron işlem ${id} iptal edildi.);
};
}, [id]); // id değiştiğinde efekti yeniden çalıştır
if (yukleniyor) return Veriler yükleniyor...;
if (!veri) return Veri bulunamadı.;
return (
Öğe: {veri.name}
Açıklama: {veri.description}
);
}
Yukarıdaki örnekte, fetchVeri adında bir async fonksiyon tanımlanır ve hemen çağrılır. En önemlisi, bir isCancelled bayrağı kullanılarak, bileşen unmount edildiğinde veya id değiştiğinde (yani efekt yeniden çalışmadan önce) asenkron işlemin sonucunun state'i güncellemesini engelleriz. Bu, "race condition" (yarış durumu) olarak bilinen bir sorunu önler; yani eski bir isteğin daha yeni bir isteğin verilerini ezmesini engeller. Bu, özellikle hızlıca değişen bağımlılıklarla çalışan veya bileşenin hızlıca mount/unmount olduğu durumlarda kritik bir optimizasyondur.
React'ta Responsive Tasarım ve useEffect
useEffect, sadece veri çekme gibi işlemler için değil, aynı zamanda responsive UI davranışlarını yönetmek için de kullanılabilir. Örneğin, ekran boyutuna göre farklı bileşenler render etmek veya stil kurallarını dinamik olarak değiştirmek isteyebilirsiniz. Temizleme fonksiyonu ile olay dinleyicilerini düzgün bir şekilde yönetmek bu tür senaryolarda çok önemlidir.
Yukarıdaki CSS örneği, farklı ekran boyutlarına göre yazı tipini ve rengi değiştiren temel bir responsive stil sağlar. useEffect ile JavaScript kullanarak da dinamik stiller uygulayabilir veya bileşenin davranışını değiştirebilirsiniz. Örneğin, belirli bir eşik değerinin altında bir mobil menü göstermek için window.innerWidth değerini takip edip bir state'i güncelleyebilirsiniz:
import React, { useEffect, useState } from 'react';
function ResponsiveMenu() {
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
};
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // Sadece ilk render'da çalışır
return (
);
}
Bu bileşen, pencere boyutunu izler ve isMobile state'ini güncelleyerek farklı menü görünümleri sunar. Böylece useEffect, sadece backend ile iletişimde değil, aynı zamanda kullanıcı arayüzünün dinamik adaptasyonunda da kritik bir rol oynar.
Sonuç
useEffect Hook'u, React fonksiyonel bileşenlerimizde yan etkileri yönetmek için paha biçilmez bir araçtır. Bileşenlerin yaşam döngüsünü modern ve bildirimsel bir yaklaşımla ele almamızı sağlayarak, veri çekme, olay dinleyicileri ekleme, DOM manipülasyonu gibi dış dünya ile etkileşimleri güvenli ve performanslı bir şekilde gerçekleştirmemize olanak tanır. Bağımlılık dizisini doğru kullanmak ve temizleme fonksiyonunun önemini anlamak, yaygın hatalardan kaçınmak ve uygulamalarınızın uzun vadeli kararlılığını sağlamak için kritik öneme sahiptir. Ayrıca, useCallback ve useMemo gibi optimizasyon araçlarıyla birlikte kullanıldığında, useEffect React uygulamalarınızın sadece işlevsel değil, aynı zamanda hızlı ve verimli olmasını da garantiler.
useEffect'in gücünü ve inceliklerini kavradıkça, daha temiz, daha bakımı kolay ve daha performanslı React bileşenleri yazma yeteneğiniz artacaktır. Bu, modern React geliştirmenin temel taşlarından biridir ve her React geliştiricisinin derinlemesine anlaması gereken bir konudur.
Sıkça Sorulan Sorular
-
useEffectneden doğrudan birasyncfonksiyon olamaz?useEffect'in callback fonksiyonu bir temizleme fonksiyonu döndürmeyi beklerken, doğrudanasyncolarak tanımlanan bir fonksiyon her zaman bir Promise döndürür. React, bu Promise'i bir temizleme fonksiyonu olarak algılayamaz, bu da beklenmedik davranışlara veya hatalara yol açabilir. Bu yüzden asenkron işlemleriuseEffectiçinde tanımlanan başka birasyncfonksiyon ile yönetmek en iyi yoldur. -
Bağımlılık dizisini boş bırakmak ile hiç bağımlılık dizisi vermemek arasındaki fark nedir?
Boş bağımlılık dizisi (
[]), efektin yalnızca bileşen ilk monte edildiğinde (mount) bir kez çalışmasını sağlar. Hiç bağımlılık dizisi vermemek ise, efektin bileşenin her yeniden render edildiğinde çalışmasına neden olur. Bu genellikle istenmeyen bir durumdur ve performans sorunlarına yol açar, çünkü her state veya prop değiştiğinde yan etki yeniden tetiklenir. -
useEffectiçindeki sonsuz döngüler nasıl önlenir?Sonsuz döngüler genellikle yanlış bağımlılık dizisi kullanımından kaynaklanır. Örneğin, bir state'i güncelleyen bir efekti, güncellediği state'i bağımlılık dizisine eklemeden kullanmak sonsuz döngüye yol açabilir. Bunu önlemek için, efektin içinde kullanılan tüm state'leri, prop'ları ve stable olmayan fonksiyonları bağımlılık dizisine eklediğinizden emin olun. Ayrıca, referans değiştiği için efekti tetikleyen nesne ve fonksiyonlar için
useCallbackveyauseMemokullanmak da döngüleri engellemeye yardımcı olur. -
Birden fazla
useEffectkullanmak iyi bir pratik midir?Evet, genellikle iyi bir pratiktir. Farklı yan etkileri (örneğin, veri çekme ve olay dinleyicisi ekleme) ayrı
useEffectHook'larına bölmek, kodun daha okunabilir, bakımı daha kolay ve daha performanslı olmasını sağlar. HeruseEffectkendi bağımlılıklarına sahip olabilir, bu da her bir yan etkinin yalnızca gerektiğinde çalışmasını garanti eder. -
useEffectyerineuseLayoutEffectne zaman kullanmalıyız?useEffect, DOM güncellemeleri ekrana yansıtıldıktan sonra asenkron olarak çalışır.useLayoutEffectise, DOM güncellemeleri ekrana yansıtılmadan hemen önce senkron olarak çalışır. Eğer DOM'u ölçmeniz, değiştirmeyi planladığınız bir stil okumanız veya tarayıcının bir sonraki boyama işleminden önce görsel bir değişikliği tetiklemeniz gerekiyorsauseLayoutEffectkullanmalısınız. Ancak çoğu yan etki içinuseEffectyeterlidir ve daha iyi performansa sahiptir.