web-dev-qa-db-fra.com

Pourquoi ne peut-on pas React Hooks être appelé à l'intérieur de boucles ou d'une fonction imbriquée?

documentation React Hooks dit de ne pas appeler Hooks à l'intérieur de boucles, de conditions ou de fonctions imbriquées.

J'ai compris que l'ordre d'exécution était important pour que React puisse savoir quel état correspond à quel appel useState. Étant donné que, il est évident qu'un hook ne peut pas être appelé à l'intérieur d'une condition.

Mais je ne vois pas quel est le problème si nous appelons useState à l'intérieur d'une boucle où le nombre d'itérations ne change pas au fil du temps. Voici un exemple :

const App = () => {
  const inputs = [];

  for(let i = 0; i < 10; i++) {
    inputs[i] = useState('name' + i);
  }

  return inputs.map(([value, setValue], index) => (
    <div key={index}> 
      <input value={value} onChange={e => setValue(e.target.value)} />
    </div>
  ));
}

export default App;

Y a-t-il un problème avec ce code ci-dessus? Et quel est le problème d'appeler useState à l'intérieur d'une fonction imbriquée, si cette fonction est appelée à chaque rendu?

10
Olivier Boissé

La référence indique la cause réelle,

En suivant cette règle, vous vous assurez que les hooks sont appelés dans le même ordre à chaque rendu d'un composant. C’est ce qui permet à React de conserver correctement l’état des hooks entre plusieurs appels useState et useEffect.

et fournit l'exemple qui montre pourquoi c'est important.

Les boucles, les conditions et les fonctions imbriquées sont des endroits courants où l'ordre d'exécution des hooks peut être perturbé. Si un développeur est sûr qu'une boucle, etc. est justifiée et garantit la commande, il n'y a pas de problème.

En fait, une boucle serait considérée comme valide hook personnalisé si elle était extraite d'une fonction:

const useInputs = n => [...Array(n)].map((_, i) => useState('name' + i));

L'exemple ci-dessus ne causera pas de problèmes mais une boucle n'est pas nécessairement justifiée; il peut s'agir d'un seul état de tableau:

const App = () => {
  const [inputs, setInputs] = useState(Array(10).fill(''));
  const setInput = (i, v) => {
    setInputs(Object.assign([...inputs], { [i]: v }));
  };

  return inputs.map((v, i) => (
    <div key={i}> 
      <input value={v} onChange={e => setInput(i, e.target.value)} />
    </div>
  ));
}
5
estus