Menu

React useEffect Hook'u: Bağımlılıklar, Temizleme, Örnekler

useEffect, React ekranı güncelledikten sonra kod çalıştırır; böylece bir bileşen React dışındaki bir şeyle senkronize olabilir: bir zamanlayıcı, bir abonelik, bir olay dinleyicisi. Bağımlılık dizisinin üç biçimini, temizlemeyi, sonsuz döngüleri ve ne zaman hiç efekte ihtiyacın olmadığını öğren.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

useEffect, React bileşenini render edip ekranı güncelledikten sonra bir kod parçasını çalıştırır. Onu bir bileşeni React dışındaki bir şeyle, örneğin bir zamanlayıcı, bir ağ bağlantısı ya da bir olay dinleyicisiyle senkronize tutmak için kullanırsın; ne zaman yeniden çalışacağını da bir bağımlılık dizisiyle kontrol edersin.

Önizlemenin altındaki konsolu aç: efekt bileşen göründüğünde bir kez, sonra her tıklamadan sonra yeniden kayıt yazar. [count]'u [] yap ve yeniden tıkla: efekt ilk kayıttan sonra sessiz kalır.

Sözdizimi

useEffect(() => {
    // setup: runs after the render is on the screen
    return () => {
        // cleanup: runs before the next setup, and on unmount
    };
}, [dependencies]);
  • İlk argüman kurulum (setup) fonksiyonudur. Bir temizleme (cleanup) fonksiyonu döndürebilir ya da hiçbir şey döndürmeyebilir.
  • İkinci argüman bağımlılık dizisidir: kurulumun okuduğu, bileşenden gelen her değer (props, state ve onlardan hesaplanan her şey).
  • useEffect'i her hook gibi bileşenin en üst düzeyinde çağır.

Efektler render'dan sonra çalışır

Render, React'in ekranın ne göstermesi gerektiğini bulmak için bileşen fonksiyonunu çağırmasıdır. Efektler bu iş bitip DOM güncellenene kadar bekler, bu yüzden bir efektin içinde sayfa yeni değerleri zaten gösteriyordur.

Her tıklama önce render'ı, sonra efekti kaydeder ve efekt React'in az önce yazdığı düğme metnini okur. DOM'u okumanın, bir zamanlayıcı başlatmanın ya da bir sunucuya bağlanmanın bileşen gövdesine değil bir efekte ait olmasının nedeni budur: gövde render sırasında, ekranda hiçbir şey yokken çalışır ve React onu beklediğinden daha sık çağırabilir.

Efektler genellikle tarayıcı ekranı boyadıktan sonra çalışır. Bir efektin DOM'u boyamadan önce ölçmesi gerektiğinde bunun yerine her zaman boyamadan önce çalışan useLayoutEffect'i kullan.

Bağımlılık dizisi: üç biçim

Bağımlılık dizisi efektin ne zaman yeniden çalışacağına karar verir. Üç biçim vardır ve bu blok farkı izleyebilmen için üçünü de kullanıyor.

Yüklenince üç efekt de kayıt yazar. a + 1'e tıkla, ikisi çalışır: dizisi olmayan ve a'ya bağlı olan. b + 1'e tıkla, yalnızca dizisi olmayan çalışır, çünkü [] ya da [a] içindeki hiçbir şey değişmedi.

Bağımlılık dizisiEfekt ne zaman çalışır
yokHer render'dan sonra
[]Bir kez, ilk render'dan sonra (mount olduğunda)
[a, b]İlk render'dan sonra, sonra a ya da b her değiştiğinde

React her bağımlılığı önceki değeriyle Object.is kullanarak karşılaştırır. Sayılar, metinler ve boolean'lar değere göre karşılaştırılır. Nesneler, diziler ve fonksiyonlar kimliğe göre karşılaştırılır; bu çok önemlidir (aşağıya bak).

Bir efekti daha seyrek çalıştırmak için bir değeri dizinin dışında bırakma. Efekt eski bir render'daki değeri kullanmaya devam ederdi. react-hooks/exhaustive-deps lint kuralı bunu yakalar; Vite'ın React şablonunun ve Next.js'in ESLint yapılandırmasının içerdiği ESLint kurulumunun parçasıdır.

Temizleme

Birçok efekt durdurulması gereken bir şey başlatır: bir bağlantı, bir abonelik, bir zamanlayıcı. Efektten bir fonksiyon döndür; React onu iki anda çağırır: efekt yeni bağımlılıklarla yeniden çalışmadan hemen önce ve bileşen ekrandan ayrıldığında (unmount).

Başka bir oda seç: konsol önce disconnect from general, sonra connect to music gösterir. Eski bağlantı yenisi açılmadan önce her zaman kapanır. Hide'a tıkla, temizleme son bir kez çalışır, çünkü ChatRoom unmount edildi.

Buradaki connect fonksiyonu gerçek bir sohbet ya da WebSocket istemcisinin yerine geçer. Biçim hepsi için aynıdır: kurulumda oluştur, temizlemede kapat.

Bir zamanlayıcıyı temizlemek

Bir efektte başlatılan zamanlayıcı, temizleme onu durdurmadıkça bileşen gittikten sonra çalışmaya devam eder.

clearInterval(id); satırını sil, sonra zamanlayıcıyı gizle: artık var olmayan bir bileşenden konsola tick gelmeye devam eder. Her Show bir tane daha başlatır.

setSeconds((s) => s + 1) ifadesine dikkat et. Efekt bir kez çalışır, bu yüzden düz bir setSeconds(seconds + 1) sonsuza kadar ilk render'daki seconds'ı okur ve 1'de durur. Updater fonksiyonu her zaman en son değeri alır.

Bir olay dinleyicisini kaldırmak

window ya da document üzerindeki olay dinleyicileri aynı kalıbı izler. removeEventListener'a addEventListener'a verdiğin fonksiyonun aynısını aktar:

useEffect(() => {
    function handleKeyDown(e) {
        if (e.key === 'Escape') onClose();
    }
    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
}, [onClose]);

Sonsuz döngü

Bağlı olduğu bir state değerini de ayarlayan bir efekt bir döngü başlatır: state değişir, React render eder, bağımlılık değişmiştir, efekt çalışır ve state'i yeniden ayarlar.

// Never stops: every render runs the effect, every effect causes a render
useEffect(() => {
    setCount(count + 1);
});

// Same loop: count changes, so the effect runs again
useEffect(() => {
    setCount(count + 1);
}, [count]);

Bileşen sonsuza kadar render olur ve sekme meşgul kalır. React bu döngüyü durdurmaz: geliştirmede konsola bir "Maximum update depth exceeded" hatası kaydeder, production'da ise hiçbir şey kaydetmez. Bu blok ikinci sürümü bir durma koşuluyla çalıştırır, böylece sayfayı dondurmadan döngüyü izleyebilirsin:

Konsol render 0'dan render 5'e kadar kayıt yazar: tek bir mount için, her biri efekt tarafından başlatılan altı render. Çözümler ne kastettiğine bağlıdır:

  • Bir kez çalışmasını istedin. [] ve updater biçimini, setCount((c) => c + 1), kullan, böylece count bir bağımlılık olmaz.
  • Başka state'ten bir değer hesaplıyorsun. Onu hiç saklama; bu sayfanın son bölümünde gösterildiği gibi render sırasında hesapla.
  • Bir kullanıcı eylemine tepki veriyorsun. Kodu olay işleyicisine koy.

Bağımlılık olarak nesneler ve fonksiyonlar

Bileşen gövdesinde oluşturulan bir nesne, dizi ya da fonksiyon her render'da yeni bir değerdir, bu yüzden ona bağlı bir efekt, içindeki hiçbir şey değişmemiş olsa bile her render'dan sonra çalışır.

Renkleri değiştirmenin aramayla hiçbir ilgisi yok, ama her değiştirme search for react'i yeniden kaydeder. options satırını efektin içine taşı ve diziyi [query] yap: değiştirmeler sessizleşir ve aramayı yalnızca input'a yazmak çalıştırır.

Genel çözüm budur. Nesneleri ve fonksiyonları onları kullanan efektin içinde oluştur ve onların oluşturulduğu ilkel değerlere bağımlı ol. Bir fonksiyonun efektin dışında yaşaması gerektiğinde useCallback kimliğini render'lar arasında sabit tutar.

Efektler geliştirmede neden iki kez çalışır

<StrictMode> açıkken (yeni bir Vite uygulaması kökü onunla sarar ve Next.js App Router onu varsayılan olarak açar) React geliştirmede bir test çalıştırır: her bileşeni mount eder, efektlerini çalıştırır, temizlemelerini çalıştırır ve efektleri yeniden çalıştırır. Yukarıdaki sohbet odası için geliştirme konsolu şunu gösterir:

connect to general
disconnect from general
connect to general

Bu bir kez, mount sırasında ve yalnızca geliştirmede olur. Temizlemesi eksik efektleri ortaya çıkarmak için vardır: art arda iki çalışma bir şeyi bozuyorsa, kullanıcı da sayfadan ayrılıp geri gelerek onu bozardı. Çözüm asla ikinci çalışmayı bir ref ile engellemek değil, temizlemeyi yazmaktır. Bu sayfadaki önizleme bir production derlemesi gibi çalışır, bu yüzden çift çalışmayı burada görmezsin.

Belki bir efekte ihtiyacın yoktur

Efektler React dışındaki sistemlerle senkronize olmak içindir. İki yaygın kullanım efektsiz daha iyidir.

Props ya da state'ten hesaplanan değerler. Onları render sırasında hesapla. Onları state'te saklayıp bir efektle senkronize etmek fazladan bir render'a mal olur ve bu render'lardan ilki DOM'a eski bir değer koyar:

Her tıklama WithEffect'i iki kez render eder ve ilk render'ı hâlâ eski adı gösterir. Computed doğru değerle bir kez render olur.

Bir kullanıcı eylemine yanıt veren kod. Bir formu göndermek, bir satın almadan sonra bir bildirim göstermek ya da bir tıklama için analitik olayı göndermek olay işleyicisine aittir. Orada tam olarak ne olduğunu bilirsin; bir efekt ise yalnızca bir değerin değiştiğini bilir.

useEffectEvent

Bazen bir efektin, o prop değiştiğinde yeniden çalışmadan bir prop'un en son değerine ihtiyacı olur. Sohbet odasında bir bildirim mevcut theme'i kullanmalı, ama temayı değiştirmek yeniden bağlanmaya yol açmamalıdır. React 19.2 bunun için useEffectEvent'i ekler:

import { useEffect, useEffectEvent } from 'react';

function ChatRoom({ roomId, theme }) {
    const onConnected = useEffectEvent(() => {
        showNotification('Connected!', theme); // always the latest theme
    });

    useEffect(() => {
        const connection = createConnection(roomId);
        connection.on('connected', () => onConnected());
        connection.connect();
        return () => connection.disconnect();
    }, [roomId]); // theme is not a dependency
}

useEffectEvent'ten gelen bir fonksiyon yalnızca efektlerin içinde çağrılmak içindir. Onu başka bileşenlere aktarma ya da bir bağımlılık dizisinde listeleme.

Sıkça Sorulan Sorular

useEffect ne zaman çalışır?

React bileşeni render edip DOM'u güncelledikten sonra, genellikle tarayıcı ekranı boyadıktan sonra. Bağımlılık dizisi olmadan her render'dan sonra, [] ile yalnızca ilkinden sonra, [a, b] ile ilk render'dan sonra ve a ya da b'nin değiştiği her render'dan sonra çalışır.

useEffect temizleme fonksiyonu nedir?

Efektten döndürdüğün fonksiyondur. React onu efekti yeni bağımlılıklarla yeniden çalıştırmadan önce ve bileşen ekrandan kaldırıldığında bir kez daha çağırır. Zamanlayıcıları temizlemek, olay dinleyicilerini kaldırmak ve abonelikleri kapatmak için kullan.

useEffect'im neden iki kez çalışıyor?

Geliştirmede <StrictMode>, temizlemesi eksik efektleri sana göstermek için her bileşeni mount eder, efektlerini çalıştırır, temizler ve yeniden çalıştırır. Bu mount sırasında bir kez ve yalnızca geliştirmede olur. Production derlemeleri efekti bir kez çalıştırır.

useEffect'im neden sonsuz döngüye giriyor?

Efekt, bağımlılık dizisinde de bulunan bir state değerini ayarlıyor (ya da hiç dizisi yok). State'i ayarlamak yeniden render eder, bağımlılık değişmiştir, bu yüzden efekt yeniden çalışır. Bir updater fonksiyonu kullanıp bağımlılığı kaldır, bir koşul ekle ya da değeri bunun yerine render sırasında hesapla.

useEffect callback'i async olabilir mi?

Hayır. Callback ya hiçbir şey ya da bir temizleme fonksiyonu döndürmelidir, async bir fonksiyon ise bir promise döndürür. Veri çekme sayfasında gösterildiği gibi efektin içinde async bir fonksiyon tanımla ve onu çağır.

Coddy programlama dilleri çizimi

Coddy ile kodlamayı öğren

BAŞLA