web-dev-qa-db-ja.com

Reactフックがループまたはネストされた関数内で呼び出されないのはなぜですか?

React Hooksのドキュメント は、ループ、条件、またはネストされた関数内でフックを呼び出さないようにと言います

Reactはどの状態がどのuseState呼び出しに対応するかを知ることができるので、実行の順序が重要であることを理解しました。それを考えると、条件内でフックを呼び出せないことは明らかです。

しかし、ループの中で繰り返し回数が変化しないループ内でuseStateを呼び出した場合、何が問題なのかわかりません。次に例を示します。

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;

上記のこのコードに問題はありますか?そして、この関数がすべてのレンダリングで呼び出される場合、ネストされた関数内でuseStateを呼び出すことの問題は何ですか?

10
Olivier Boissé

参照 は実際の原因を示し、

このルールに従うことで、コンポーネントがレンダリングされるたびにフックが同じ順序で呼び出されるようになります。これが、Reactが複数のuseState呼び出しとuseEffect呼び出しの間のフックの状態を正しく保持することを可能にするものです。

これが重要である理由を示す を提供します。

ループ、条件、入れ子関数は、フックが実行される順序が乱れる可能性がある一般的な場所です。ループなどが正当化され、順序が保証されていることを開発者が確信している場合、問題はありません。

実際、ループが関数に抽出された場合、ループは有効と見なされます カスタムフック

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

上記の例では問題は発生しませんが、ループが必ずしも正当化されるわけではありません。単一のアレイ状態にすることができます。

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