tepki kancaları useEffect () temizleme yalnızca componentWillUnmount?


94

Sorunumu kolayca sormak için bu kodun sonucunu açıklayayım.

const ForExample = () => {
    const [name, setName] = useState('');
    const [username, setUsername] = useState('');

    useEffect(() => {
        console.log('effect');
        console.log({
            name,
            username
        });

        return () => {
            console.log('cleaned up');
            console.log({
                name,
                username
            });
        };
    }, [username]);

    const handleName = e => {
        const { value } = e.target;

        setName(value);
    };

    const handleUsername = e => {
        const { value } = e.target;

        setUsername(value);
    };

    return (
        <div>
            <div>
                <input value={name} onChange={handleName} />
                <input value={username} onChange={handleUsername} />
            </div>
            <div>
                <div>
                    <span>{name}</span>
                </div>
                <div>
                    <span>{username}</span>
                </div>
            </div>
        </div>
    );
};

Bağlandığında ForExample component, 'etki' günlüğe kaydedilecektir. Bu componentDidMount().

Ve ad girişini her değiştirdiğimde, hem 'efekt' hem de 'temizlenmiş' günlüğe kaydedilecek. Bunun tersi, [username]ikinci parametresine eklediğimden beri kullanıcı adı girişini değiştirdiğimde hiçbir mesaj günlüğe kaydedilmeyecek useEffect(). Bu,componentDidUpdate()

Son olarak, kaldırıldığında ForExample component, 'temizlendi' günlüğe kaydedilir. Bu componentWillUnmount().

Hepimiz bunu biliyoruz.

Özetlemek gerekirse, bileşen her yeniden oluşturulduğunda 'temizlendi' çağrılır (ayırma dahil)

Bu bileşenin yalnızca bağlantısı kesildiği an için 'temizlenmiş' olarak günlüğe kaydedilmesini istersem, ikinci parametresini olarak değiştirmem useEffect()gerekir [].

Ama ben değişim [username]için [], ForExample componentartık aletlerin componentDidUpdate()isim girişi için.

Yapmak istediğim şey, bileşenin hem componentDidUpdate()isim girişi hem de componentWillUnmount(). (yalnızca bileşenin kaldırıldığı an için günlük 'temizlendi')


4
2 ayrı efektiniz olabilir. İçeren bir dizi verilir bir usernameikinci bağımsız değişken olarak, içinde, ve ikinci bağımsız değişken olarak boş bir dizi verilir bir.
Tholle

@Tholle 2 ayrı useEffect () yöntemi yapmam gerektiğini mi söylüyorsunuz?
koo

1
Evet, bunu yapmanın bir yolu bu.
Tholle

1
@Tholle Son useEffect () yöntemi tarafından geçersiz kılınacağını düşündüm. Deneyeceğim. Teşekkürler
koo

2
Harika! Rica ederim. Temizliğin ne yapması gerektiğine bağlıdır. 2 ayrı efekt kötü bir çözüm değildir.
Tholle

Yanıtlar:


88

Temizleme işlemine bağlı olmadığından username, temizlemeyi useEffectikinci argüman olarak boş bir dizi verilen ayrı bir diziye koyabilirsiniz .

Misal

const { useState, useEffect } = React;

const ForExample = () => {
  const [name, setName] = useState("");
  const [username, setUsername] = useState("");

  useEffect(
    () => {
      console.log("effect");
    },
    [username]
  );

  useEffect(() => {
    return () => {
      console.log("cleaned up");
    };
  }, []);

  const handleName = e => {
    const { value } = e.target;

    setName(value);
  };

  const handleUsername = e => {
    const { value } = e.target;

    setUsername(value);
  };

  return (
    <div>
      <div>
        <input value={name} onChange={handleName} />
        <input value={username} onChange={handleUsername} />
      </div>
      <div>
        <div>
          <span>{name}</span>
        </div>
        <div>
          <span>{username}</span>
        </div>
      </div>
    </div>
  );
};

function App() {
  const [shouldRender, setShouldRender] = useState(true);

  useEffect(() => {
    setTimeout(() => {
      setShouldRender(false);
    }, 5000);
  }, []);

  return shouldRender ? <ForExample /> : null;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>


güzel ve temiz bir örnek. Yine de merak ediyorum. Değişen gezinme üzerinde bir şekilde bir kullanım efekti tetikleyebilir miyim, yoksa onu bileşenler ağacında yukarı taşımak zorunda mıyım? Çünkü sadece "temizlenmiş" kullanım etkinizi yapıştırırken bu tetikleyiciyi görmüyorum.
Fabian Bosler

122

birden fazla kullanım kullanabilirsiniz

örneğin değişkenim data1 ise bunların hepsini bileşenimde kullanabilirim

useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );

5
ilk ve son useEffects arasındaki fark nedir, ilk useEffect willmount veya didmount üzerinde çağrılır , son useEffect boş dizi ile geri çağırma işlevi döndürüldü neden? Etkili kullanım durumlarını ne zaman ve nasıl kullanabileceğimizi detaylandırır mısınız?
siluveru kiran kumar

4
@siluverukirankumar Bir geri aramanın dönüş değeri (işlev), destroy (unmount olayı) sırasında çağrılan şeydir. Bu yüzden son örnek bir HOC, hemen dönen bir fonksiyondur. İkinci parametre, React'in bu kancayı yeniden çalıştırmak için değişiklikleri arayacağı yerdir. Boş bir dizi olduğunda sadece bir kez çalışır.
Georgy

3
Teşekkürler @Georgy son kullanımdaEfekt geri aramayı geri
veriyor

2
Öyleyse, bir useEffect kancası yaparsanız ve bir işlev döndürürse, döndürülen işlevden önceki kod bir componentDidMount olarak çalışır ... ve döndürülen işlevdeki kod componentWillUnmount? Biraz kafa karıştırıcı, bu yüzden doğru anladığımdan emin olmak. useEffect (() => {// mount üzerinde çalıştırılacak kod ... return () => {// dismount çalıştıracak kod}}) Bu doğru mu?
Maiya

Overreacted.io/a-complete-guide-to-useeffect'i okumayı öneriyorum Yaşam döngülerindeki kancaları düşünmek gerçekten o kadar tatlı değil
moto

2
function LegoComponent() {

  const [lego, setLegos] = React.useState([])

  React.useEffect(() => {
    let isSubscribed = true
    fetchLegos().then( legos=> {
      if (isSubscribed) {
        setLegos(legos)
      }
    })
    return () => isSubscribed = false
  }, []);

  return (
    <ul>
    {legos.map(lego=> <li>{lego}</li>)}
    </ul>
  )
}

Yukarıdaki kodda, fetchLegos işlevi bir söz verir. UseEffect kapsamında bir koşul uygulayarak, bileşenin bağlantısı kesildikten sonra uygulamanın durumunu ayarlamasını önleyerek sözü "iptal edebiliriz".

Uyarı: Bağlanmayan bir bileşende React durum güncellemesi gerçekleştirilemez. Bu işlem yok, ancak uygulamanızda bir bellek sızıntısı olduğunu gösteriyor. Düzeltmek için, bir useEffect temizleme işlevindeki tüm abonelikleri ve zaman uyumsuz görevleri iptal edin.


1

çok fazla karmaşık işlev ve yöntem oluşturmak yerine yaptığım şey bir olay dinleyicisi oluşturmak ve bunu manuel olarak yapma konusunda endişelenmeden benim için otomatik olarak bağlama ve ayırma işlemlerini yapmaktır. İşte bir örnek.

//componentDidMount
useEffect( () => {

    window.addEventListener("load",  pageLoad);

    //component will unmount
    return () => {
       
        window.removeEventListener("load", pageLoad);
    }

 });

şimdi bu kısım bittiğine göre pageLoad fonksiyonundan istediğim her şeyi böyle çalıştırıyorum.

const pageLoad = () =>{
console.log(I was mounted and unmounted automatically :D)}

0

useEffect kendi kapsamı içinde izole edilir ve buna göre oluşturulur. Https://reactjs.org/docs/hooks-custom.html adresinden görüntü

görüntü açıklamasını buraya girin


Bir çözüme bağlantı memnuniyetle karşılanır, ancak lütfen cevabınızın o olmadan yararlı olduğundan emin olun: Bağlantının etrafına bağlam ekleyin, böylece kullanıcı arkadaşlarınız bunun ne olduğu ve neden orada olduğu konusunda fikir sahibi olurlar, ardından sayfanın en alakalı bölümünü alıntılayın ' hedef sayfanın mevcut olmaması durumunda yeniden bağlanma. Bir bağlantıdan biraz daha fazla olan cevaplar silinebilir .
Богдан Опир
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.