63

次のコンポーネントの場合、年齢セレクターを押して値を 15 に変更すると、運転免許証フィールドのないフォームをレンダリングすると、エラーが発生します。

Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
    at invariant (react-dom.development.js:55)
    at finishHooks (react-dom.development.js:11581)
    at updateFunctionComponent (react-dom.development.js:14262)
    at beginWork (react-dom.development.js:15103)
    at performUnitOfWork (react-dom.development.js:17817)
    at workLoop (react-dom.development.js:17857)
    at HTMLUnknownElement.callCallback (react-dom.development.js:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
    at invokeGuardedCallback (react-dom.development.js:256)
    at replayUnitOfWork (react-dom.development.js:17113)
    at renderRoot (react-dom.development.js:17957)
    at performWorkOnRoot (react-dom.development.js:18808)
    at performWork (react-dom.development.js:18716)
    at flushInteractiveUpdates$1 (react-dom.development.js:18987)
    at batchedUpdates (react-dom.development.js:2210)
    at dispatchEvent (react-dom.development.js:4946)
    at interactiveUpdates$1 (react-dom.development.js:18974)
    at interactiveUpdates (react-dom.development.js:2217)
    at dispatchInteractiveEvent (react-dom.development.js:4923)

以下のコード例:

const {useState} = React;

function App() {
  const [name, setName] = useState('Mary');
  const [age, setAge] = useState(16);

  if (age < 16) {
    return (
      <div>
        Name:{' '}
        <input
          value={name}
          onChange={e => {
            setName(e.target.value);
          }}
        />
        <br />
        Age:{' '}
        <input
          value={age}
          type="number"
          onChange={e => {
            setAge(+e.target.value);
          }}
        />
      </div>
    );
  }

  const [license, setLicense] = useState('A123456');

  return (
    <div>
      Name:{' '}
      <input
        value={name}
        onChange={e => {
          setName(e.target.value);
        }}
      />
      <br />
      Age:{' '}
      <input
        value={age}
        type="number"
        onChange={e => {
          setAge(+e.target.value);
        }}
      />
      <br />
      Driver License:{' '}
      <input
        value={license}
        onChange={e => {
          setLicense(e.target.value);
        }}
      />
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>

4

5 に答える 5

84

問題は、最初のレンダリングで 3 つのuseStateフックが呼び出されたということです -がname、age が 16 未満の値に変更された後、forは呼び出されなくなり、最初の 2 つのフックのみが呼び出されます。React ドキュメントの状態として:agelicenseuseStatelicense

ループ、条件、またはネストされた関数内でフックを呼び出さないでください。代わりに、常に React 関数のトップレベルでフックを使用してください。このルールに従うことで、コンポーネントがレンダリングされるたびにフックが同じ順序で呼び出されるようになります。これにより、React は複数のuseStateコールuseEffect間でフックの状態を正しく保持できます。

呼び出されるフックの順序は重要です。フックが呼び出されないようにするコードを記述すると、React はフック呼び出しとその値を一致させることができなくなります。

解決策は、フックを関数の先頭に移動しlicenseて、必要かどうかに関係なく呼び出されるようにすることです。

const {useState} = React;

function App() {
  const [name, setName] = useState('Mary');
  const [age, setAge] = useState(16);
  const [license, setLicense] = useState('A123456');

  return (
    <div>
      Name:{' '}
      <input
        value={name}
        onChange={e => {
          setName(e.target.value);
        }}
      />
      <br />
      Age:{' '}
      <input
        value={age}
        type="number"
        onChange={e => {
          setAge(+e.target.value);
        }}
      />
      {age >= 16 && <span>
        <br />
        Driver License:{' '}
        <input
          value={license}
          onChange={e => {
            setLicense(e.target.value);
          }}
        /></span>
       }
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>

于 2018-11-25T22:51:06.877 に答える
5

そのため、このエラーも発生しましたが、フックが条件でラップされていることとは関係ありませんでした。代わりに、キー値が正しくないことが原因でした。

あるリストから別のリストにアイテムをドラッグ アンド ドロップして移動するコンポーネントがありました。ただし、これらのアイテムの一部はロックされていたので、それらの要素のフックへの参照を削除しました。

問題は、インデックスをキーとして使用したため、新しい要素を上にドラッグすると、ロックされた要素と同じキーが取得され、ref の値が変更され、React が上記のエラーを訴えたことでした。

したがって、この問題に遭遇した人への私の答えは、本当に一意のキーがあるかどうかを確認することです!

于 2020-08-05T15:11:05.913 に答える
0

今日、私はこのエラーに遭遇しました。フックの位置を変更して修正しました:useEffect()関数の中央からヘッダーに。また、ループ内でフックを使用しないでください。

特定の値が再レンダリング間で変更されていない場合、エフェクトの適用をスキップするように React に指示できます。これを行うには、配列をオプションの 2 番目の引数として useEffect に渡します。

      useEffect( () => {
        dispatch({type: 'GET_PAGE', slug: Param});
        setPagedata( data );
      });


      useEffect( () => {
        dispatch({type: 'GET_PAGE', slug: Param});
      }, [Param]);

      useEffect( () => {
        setPagedata( data );
      }, [data]);

そしてそれはうまくいきます!

于 2021-09-05T03:51:30.137 に答える