web-dev-qa-db-fra.com

Exemple d'utilisation du crochet useEffect: Qu'est-ce qui cause le nouveau rendu?

J'essaie de comprendre quand useEffect provoque un rendu. Je suis très surpris du résultat de l'exemple suivant:

https://codesandbox.io/embed/romantic-Sun-j5i4m

function useCounter(arr = [1, 2, 3]) {
  const [counter, setCount] = useState(0);
  useEffect(() => {
    for (const i of arr) {
      setCount(i);
      console.log(counter);
    }
  }, [arr]);
}

function App() {
  useCounter();
  console.log("render");
  return <div className="App" />;
}

Le résultat de cet exemple est le suivant:

enter image description here

Ma confusion vient de deux choses: je ne sais pas pourquoi:

  1. Le composant ne s'affiche que trois fois (j'aurais pensé que le composant se rendrait à chaque appel à setCount + un rendu initial - donc 4 fois)
  2. Le compteur n'a que deux valeurs 0 et 3: je suppose que, comme l'indique cet article , chaque rendu voit son propre état et ses propres accessoires, de sorte que la boucle entière sera exécutée avec chaque état comme constante (1, 2, 3) -> Mais pourquoi l'État n'est-il jamais 2?

Je serais super heureux si quelqu'un pouvait clarifier. Merci!

12
Xen_mar

Il y a une coïncidence qui pourrait créer une certaine confusion dans le problème d'origine. Principalement le fait qu'il existe 3 rendus et que le useCounter a un paramètre de longueur par défaut égal à 3. Ci-dessous, vous pouvez voir que même pour un tableau plus grand, il n'y aura que 3 rendus.

function useCounter(arr = [1, 2, 3, 4 , 5 , 6]) {
  const [counter, setCount] = React.useState(0);
  React.useEffect(() => {
    for (const i of arr) {
      setCount(i);
      console.log(counter);
    }
  }, [arr]);
}

function App() {
  useCounter();
  console.log("render");
  return <div className = "App" / > ;
}

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

Une autre confusion peut être créée par le fait que le setState est appelé à chaque fois, sauf le premier, avec la même valeur (la dernière valeur du tableau), ce qui annule pratiquement le rendu. Si toutefois le setState était appelé avec des valeurs différentes, le flux présenté créerait une boucle infinie :)

car chaque autre render déclenche un useEffect qui déclenche un setSate qui déclenche un render qui déclenche un useEffect et ainsi de suite.

J'espère que cela rend les choses plus claires pour quelqu'un.

0
bluehipy