UseEffect React Hook kullanırken eksik bağımlılık uyarısı nasıl düzeltilir?


180

React 16.8.6 ile (önceki sürüm 16.8.3'te iyiydi), bir getirme isteğinde sonsuz bir döngüyü önlemeye çalıştığımda bu hatayı alıyorum

./src/components/BusinessesList.js
Line 51:  React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array  react-hooks/exhaustive-deps

Sonsuz döngüyü durduran bir çözüm bulamadım. Kullanmaktan uzak durmak istiyorum useReducer(). Bu tartışmayı buldum https://github.com/facebook/react/issues/14920 nerede olası bir çözüm You can always // eslint-disable-next-line react-hooks/exhaustive-deps if you think you know what you're doing.yaptığımdan emin değilim, bu yüzden henüz uygulamayı denemedim.

Bu geçerli kurulum var React hook useEffect sürekli sonsuza kadar çalışır / sonsuz döngü ve tek yorum hakkında useCallback()değil aşina değilim.

Şu anda nasıl kullanıyorum useEffect()(başlangıçta sadece bir kez çalıştırmak istiyorum componentDidMount())

useEffect(() => {
    fetchBusinesses();
  }, []);
const fetchBusinesses = () => {
    return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };

Yanıtlar:


193

Efekt dışında bir yerde fetchBusinesses yöntemini kullanmıyorsanız, efekti taşıyabilir ve uyarıyı önleyebilirsiniz.

useEffect(() => {
    const fetchBusinesses = () => {
       return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };
  fetchBusinesses();
}, []);

Ancak render dışında fetchBusinesses kullanıyorsanız iki şeyi not etmelisiniz

  1. Eğer herhangi bir sorun var mı yok geçirerek fetchBusinessesonun kapsayan kapanması ile monte sırasında kullanılan zaman bir yöntem olarak?
  2. Metodunuz çevreleyen kapanışından aldığı bazı değişkenlere mi bağlı? Bu senin için geçerli değil.
  3. Her render işleminde fetchBusinesses yeniden oluşturulacak ve dolayısıyla useEffect'e geçirilmesi sorunlara neden olacaktır. Eğer bağımlılık dizisine geçirmek için ilk önce fetchBusinesses ezberlemek gerekir.

Özetlemek gerekirse, fetchBusinessesdışarıda useEffectkullanıyorsanız kuralı devre dışı bırakabileceğinizi söyleyebilirim, // eslint-disable-next-line react-hooks/exhaustive-depsaksi takdirde yöntemi kullanımın içine taşıyabilirsiniz.

Kuralı devre dışı bırakmak için şöyle yazarsınız

useEffect(() => {
   // other code
   ...

   // eslint-disable-next-line react-hooks/exhaustive-deps
}, []) 

14
Güzel özetlediğiniz çözümü kullandım. Farklı bir kurulum nedeniyle başka yerde kullandığım başka bir çözüm useCallback(). Yani örneğin: const fetchBusinesses= useCallback(() => { ... }, [...]) ve şu useEffect()şekilde görünecektir:useEffect(() => { fetchBusinesses(); }, [fetchBusinesses]);
russ

1
@russ, haklısın, bağımlılık dizisine geçirmek için useCallback kullanarak fetchBusiness'ı not etmeniz gerekir
Shubham Khatri

Eslint-devre dışı bırakma ifadesini nereye koyacağınızı göstermeniz güzel olurdu. Kullanımın üstünde olacağını düşündümEffect
user210757

1
kullanarak // eslint-disable-next-line react-hooks/exhaustive-depskod doğru olduğunu linter anlatmaya kesmek gibidir. Ben bir argümanı zorunlu olmadığında tespit etmek için yeterince akıllı yapmak için başka bir çözüm bulmak umuyoruz
umuyoruz Olivier Boissé

1
@TapasAdhikary, evet kullanımda bir zaman uyumsuz işlevi olabilir.Etkileş, sadece farklı yazmanız gerekir. Lütfen stackoverflow.com/questions/53332321/…
adresini ziyaret

76
./src/components/BusinessesList.js
Line 51:  React Hook useEffect has a missing dependency: 'fetchBusinesses'.
Either include it or remove the dependency array  react-hooks/exhaustive-deps

JS / React hatası değil, eslint (eslint-plugin-tepki-kanca) uyarısı.

Kancanın işleve bağlı olduğunu söylüyor fetchBusinesses, bu yüzden onu bağımlılık olarak geçmelisiniz.

useEffect(() => {
  fetchBusinesses();
}, [fetchBusinesses]);

Eğer işlev aşağıdaki gibi bir bileşende bildirilirse, her bir render işlevini çağırır.

const Component = () => {
  /*...*/

  //new function declaration every render
  const fetchBusinesses = () => {
    fetch('/api/businesses/')
      .then(...)
  }

  useEffect(() => {
    fetchBusinesses();
  }, [fetchBusinesses]);

  /*...*/
}

çünkü her defasında işlev yeni referansla yeniden bildirilir

Bu işi yapmanın doğru yolu:

const Component = () => {
  /*...*/

  // keep function reference
  const fetchBusinesses = useCallback(() => {
    fetch('/api/businesses/')
      .then(...)
  }, [/* additional dependencies */]) 

  useEffect(() => {
    fetchBusinesses();
  }, [fetchBusinesses]);

  /*...*/
}

veya sadece useEffect

Daha fazla: https://github.com/facebook/react/issues/14920


14
Bu yeni bir hata ile sonuçlanıyorLine 20: The 'fetchBusinesses' function makes the dependencies of useEffect Hook (at line 51) change on every render. Move it inside the useEffect callback. Alternatively, wrap the 'fetchBusinesses' definition into its own useCallback() Hook
russ

1
çözüm gayet iyi ve eğer işlev üzerinde başka bir durumu değiştirirseniz, başka bir beklenmedik davranıştan kaçınmak için bağımlılıkları eklemelisiniz
cesarlarsson

58

Doğrudan useEffectgeri arama olarak ayarlayabilirsiniz :

useEffect(fetchBusinesses, [])

Yalnızca bir kez tetikleyecektir, bu nedenle tüm işlev bağımlılıklarının doğru ayarlandığından emin olun (kullanmakla aynı componentDidMount/componentWillMount...)


Düzenle 02/21/2020

Sadece bütünlük için:

1. useEffectGeri arama işlevi kullanın (yukarıdaki gibi)

useEffect(fetchBusinesses, [])

2. içinde beyan fonksiyonu useEffect()

useEffect(() => {
  function fetchBusinesses() {
    ...
  }
  fetchBusinesses()
}, [])

3. ile not edin useCallback()

Bu durumda, işlevinizde bağımlılıklar varsa, bunları useCallbackbağımlılık dizisine dahil etmeniz gerekir useEffectve işlevin parametreleri değiştiğinde bu yeniden tetiklenir . Ayrıca, bir çok kazan plakası ... Yani fonksiyonu doğrudan olduğu useEffectgibi geçirin 1. useEffect(fetchBusinesses, []).

const fetchBusinesses = useCallback(() => {
  ...
}, [])
useEffect(() => {
  fetchBusinesses()
}, [fetchBusinesses])

4. Eslint'in uyarısını devre dışı bırakın

useEffect(() => {
  fetchBusinesses()
}, []) // eslint-disable-line react-hooks/exhaustive-deps

2
Seni seviyorum ... Bu cevap çok eksiksiz!
Nick09

8

Çözüm ayrıca tepki ile verilir useCallback, işlevinizin bir not sürümünü döndürecek şekilde kullanmanızı önerirler:

'FetchBusinesses' işlevi her bağımlılıkta useEffect Hook (NN satırında) değişikliğinin bağımlılıklarını yapar. Bunu düzeltmek için, 'fetchBusinesses' tanımını kendi kullanımına sarın

useCallbackkullanımı kolaydır, çünkü useEffectfarkı aynı işlevi useCallback bir işlevi döndürür. Şöyle görünecektir:

 const fetchBusinesses = useCallback( () => {
        return fetch("theURL", {method: "GET"}
    )
    .then(() => { /* some stuff */ })
    .catch(() => { /* some error handling */ })
  }, [/* deps */])
  // We have a first effect thant uses fetchBusinesses
  useEffect(() => {
    // do things and then fetchBusinesses
    fetchBusinesses(); 
  }, [fetchBusinesses]);
   // We can have many effect thant uses fetchBusinesses
  useEffect(() => {
    // do other things and then fetchBusinesses
    fetchBusinesses();
  }, [fetchBusinesses]);



1

2. bağımsız değişken türü dizisini kaldırabilirsiniz, []ancak fetchBusinesses()her güncelleştirme de denir. İsterseniz uygulamaya bir IFifade ekleyebilirsiniz fetchBusinesses().

React.useEffect(() => {
  fetchBusinesses();
});

Diğeri ise fetchBusinesses()bileşeni bileşeninizin dışında uygulamaktır . fetchBusinesses(dependency)Varsa , çağrınıza herhangi bir bağımlılık argümanı iletmeyi unutmayın .

function fetchBusinesses (fetch) {
  return fetch("theURL", { method: "GET" })
    .then(res => normalizeResponseErrors(res))
    .then(res => res.json())
    .then(rcvdBusinesses => {
      // some stuff
    })
    .catch(err => {
      // some error handling
    });
}

function YourComponent (props) {
  const { fetch } = props;

  React.useEffect(() => {
    fetchBusinesses(fetch);
  }, [fetch]);

  // ...
}

0

Aslında, kancalarla geliştirdiğinizde uyarılar çok kullanışlıdır. ancak bazı durumlarda, size iğne yapabilir. özellikle bağımlılık değişikliği dinlemeniz gerekmediğinde.

fetchBusinessesKancanın bağımlılıklarının içine koymak istemiyorsanız , kancanın geri aramasına bağımsız değişken olarak iletebilir ve ana öğeyi fetchBusinessesbunun için varsayılan değer olarak ayarlayabilirsiniz.

useEffect((fetchBusinesses = fetchBusinesses) => {
   fetchBusinesses();
}, []);

En iyi uygulama değildir, ancak bazı durumlarda yararlı olabilir.

Ayrıca Shubnam'ın yazdığı gibi, ESLint'e kanca kontrolünü yok saymasını söylemek için aşağıdaki kodu ekleyebilirsiniz.

// eslint-disable-next-line react-hooks/exhaustive-deps

0

Sadece [çalıştırmak istiyorum fetchBusinesses] kez başlayan benzer içindecomponentDidMount()

fetchBusinessesBileşeninizden tamamen çekebilirsiniz :

const fetchBusinesses = () => { // or pass some additional input from component as args
  return fetch("theURL", { method: "GET" }).then(n => process(n));
};

const Comp = () => {
  React.useEffect(() => {
    fetchBusinesses().then(someVal => {
      // ... do something with someVal
    });
  }, []); // eslint warning solved!
  return <div>{state}</div>;
};

Bu sadece basit bir çözüm sağlamakla kalmayacak ve kapsamlı debi uyarılarını çözecektir. fetchBusinessşimdi CompReact ağacının dışındaki modül kapsamında olduğu için daha iyi test edilebilir ve hafifletilebilir .

fetchBusinessesDışarıya taşınma burada iyi çalışıyor, çünkü sadece eski kapatma kapsamı ( dep in ) nedeniyle bileşenden ilk sahne ve durumu okuyabiliyoruz .[]useEffect

İşlev bağımlılıkları nasıl atlanır

  • İşlevi efektin içinde taşıma
  • İşlevi bileşenin dışına taşı - (bunu kullanıyoruz)
  • Oluşturma sırasında çağrı fonksiyonu ve useEffectbu değere bağlı izin (saf hesaplama fonksiyonu)
  • Derinlikleri etkilemek için fonksiyon ekleyin ve useCallbackson çare olarak sarın

Diğer çözümlerle ilgili olarak:

Çekme fetchBusinessesiçini useEffect()Eğer içinde diğer durumuna erişmek eğer gerçekten yardımcı olmuyor. eslint yine şikayet ediyor: Codesandbox .

Ben de eslint ayrıntılı-deps geri tutmak yorum yoksay. Bağımlılıklarınızı biraz yeniden düzenlediğinizde ve elden geçirdiğinizde unutmak kolaydır.


0
const [mount, setMount] = useState(false)
const fetchBusinesses = () => { 
   //function defination
}
useEffect(() => {
   if(!mount) {
      setMount(true);
      fetchBusinesses();
   }
},[fetchBusinesses]);

Bu çözüm oldukça basittir ve es-lint uyarılarını geçersiz kılmanıza gerek yoktur. Bileşenin takılı olup olmadığını kontrol etmek için bir bayrak bulundurun.


0

bu şekilde dene

const fetchBusinesses = () => {
    return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };

ve

useEffect(() => {
    fetchBusinesses();
  });

iş senin için. Ama benim önerim bu şekilde denemek de sizin için çalışıyor. Öncekinden daha iyi. Bu şekilde kullanıyorum:

useEffect(() => {
        const fetchBusinesses = () => {
    return fetch("theURL", {method: "GET"}
    )
      .then(res => normalizeResponseErrors(res))
      .then(res => {
        return res.json();
      })
      .then(rcvdBusinesses => {
        // some stuff
      })
      .catch(err => {
        // some error handling
      });
  };
        fetchBusinesses();
      }, []);

belirli bir kimliğin temelinde veri alırsanız, geri arama kullanımına ekleyin.Etkinlik [id]sonra uyarı gösteremez React Hook useEffect has a missing dependency: 'any thing'. Either include it or remove the dependency array


-4

sonraki satır için eslint'i devre dışı bırakmanız yeterlidir;

useEffect(() => {
   fetchBusinesses();
// eslint-disable-next-line
}, []);

bu şekilde, tıpkı bir bileşen monte edildiği gibi kullanıyorsunuz (bir kez denir)

güncellenmiş

veya

const fetchBusinesses = useCallback(() => {
 // your logic in here
 }, [someDeps])

useEffect(() => {
   fetchBusinesses();
// no need to skip eslint warning
}, [fetchBusinesses]); 

someDeps her değiştiğinde fetchBusinesses çağrılır


devre dışı bırakmak yerine, sadece bunu yapmak: [fetchBusinesses]uyarıyı otomatik olarak kaldıracak ve bu benim için sorunu çözdü.
rotimi-en iyi

7
@RotimiBest - bunu yapmak, soruda açıklandığı gibi sonsuz bir yeniden oluşturmaya neden olur
user210757

Aslında bunu bir süre önce projelerimden birinde yaptım ve sonsuz bir döngü üretmedi. Yine de kontrol edecek.
rotimi-best

@ user210757 Bekleyin ama neden sonsuz bir döngüye neden olacak, sunucudan veri alındıktan sonra durumu ayarladığınız gibi değil. Durumu güncelliyorsanız, işlevi çağırmadan önce useEffectdurumun boş olup olmadığını kontrol eden bir if durumu yazmanız yeterlidir .
rotimi-best

@ rotimi-en iyi ben yorum beri yana olmuştur ama işlev her zaman yeniden oluşturulduğunu söyleyebilirim, böylece useEffect gövdeye veya useCallback
user210757 26:18 de
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.