web-dev-qa-db-fra.com

Boucle infinie en cours d'utilisationEffect

Je m'amuse avec le nouveau système de hook dans React 16.7-alpha et reste bloqué dans une boucle infinie dans useEffect lorsque l'état que je gère est un objet ou un tableau.

D'abord, j'utilise useState et l'initie avec un objet vide comme celui-ci:

const [obj, setObj] = useState({});

Ensuite, dans useEffect, j'utilise setObj pour le définir à nouveau sur un objet vide. En second argument, je passe [obj], en espérant qu'il ne sera pas mis à jour si le contenu de l'objet n'a pas changé. Mais cela continue à se mettre à jour. Je suppose que, peu importe le contenu, ce sont toujours des objets différents qui font que React pense que cela change continuellement?

useEffect(() => {
  setIngredients({});
}, [ingredients]);

La même chose est vraie avec les tableaux, mais en tant que primitive, elle ne restera pas bloquée dans une boucle, comme prévu.

À l'aide de ces nouveaux points d'ancrage, comment dois-je gérer les objets et les tableaux lors de la vérification de la modification ou non du contenu?

9
Tobias Haugen

Le passage d'un objet vide ou d'un tableau vide en tant que second argument à utiliserEffect le fait uniquement s'exécuter sur les montages et les montages, arrêtant ainsi les boucles infinies.

useEffect(() => {
  setIngredients({});
}, {});

Cela m’a été clarifié dans l’article de blog sur les crochets React à https://www.robinwieruch.de/react-hooks/

9
Tobias Haugen

Avait le même problème. Je ne sais pas pourquoi ils n'en parlent pas dans les documents. Je veux juste ajouter un peu à la réponse de Tobias Haugen. 

Pour exécuter quoi que ce soit une seule fois, vous devez utiliser:

  useEffect(() => {

    // do anything only one time if you pass empty array []
  }, [] )

Pour exécuter quoi que ce soit une fois sur le montage du composant et sur certaines données uniquement

  const [data, setData] = useState(false)
  useEffect(() => {

    // if you pass some variable, than component will rerender second time if this(in my case data) is changed
  }, [data] )
4
RTW

Comme indiqué dans la documentation ( https://reactjs.org/docs/hooks-effect.html ), le hook useEffect est destiné à être utilisé lorsque vous souhaitez que du code soit exécuté après chaque rendu . De la docs:

Est-ce que useEffect est exécuté après chaque rendu? Oui!

Si vous souhaitez personnaliser cela, vous pouvez suivre les instructions qui apparaissent plus tard dans la même page ( https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects ). En gros, la méthode useEffect accepte un argument de second que React examinera pour déterminer si l’effet doit être déclenché à nouveau ou non.

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes

Vous pouvez passer n'importe quel objet comme second argument. Si cet objet reste inchangé, votre effet ne sera déclenché qu'après le premier montage. Si l'objet change, l'effet sera déclenché à nouveau.

2
Rocío García Luque

J'ai rencontré le même problème une fois de plus et je l'ai corrigé en m'assurant de transmettre les valeurs primitives dans le deuxième argument [].

Si vous transmettez un objet, React stockera uniquement la référence à l'objet et exécutera l'effet lorsque la référence changera, ce qui correspond généralement à une heure donnée (mais je ne sais pas comment.

La solution consiste à transmettre les valeurs dans l'objet. Tu peux essayer,

const obj = { keyA: 'a', keyB: 'b' }

useEffect(() => {
  // do something
}, [Object.values(obj)]);

ou

const obj = { keyA: 'a', keyB: 'b' }

useEffect(() => {
  // do something
}, [obj.keyA, obj.keyB]);
1
Dinesh Pandiyan