React: eslint-plugin-react-hooks: 'フックは条件付きで呼び出されています'条件外のエラー

作成日 2019年09月19日  ·  4コメント  ·  ソース: facebook/react

機能をリクエストしバグを報告しますか?

バグ(おそらく)

現在の動作は何ですか?

プラグインはこのエラーを示しています:

Reactフック「useState」は条件付きで呼び出されます。 React Hookは、すべてのコンポーネントレンダリングでまったく同じ順序で呼び出す必要があります。 早期に戻った後、誤ってReact Hookを呼び出しましたか? (react-hooks / rules-of-hooks)eslint

しかし、条件付きでフックを呼んでいるとは思いません。

コード:

https://codesandbox.io/s/exciting-bhabha-mqj7q

function App(props) {
  const someObject = { propA: true, propB: false };

  for (const propName in someObject) {
    if (propName === true) {
      console.log("something");
    } else {
      console.log("whatever");
    }
  }

  // THE PLUGIN ERROR MSG ON THIS useState
  const [myState, setMyState] = useState(null);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

image

期待される動作は何ですか?

この状況では、プラグインはエラーを表示しません。

Reactのどのバージョン、およびどのブラウザ/ OSがこの問題の影響を受けますか?

image

ESLint Rules Bug

最も参考になるコメント

全てのコメント4件

この特定の例では、次のことに気づきました。

pathsFromStartToEnd3
allPathsFromStartToEnd2

また、 possiblyHasEarlyReturntrue


この特定のエラーは、 pathsFromStartToEndallPathsFromStartToEndが等しくない場合に報告されます。

RulesOfHooks.jsの404行を参照してください


for..inループ内のコードを別の関数に抽象化すると、lintエラーはなくなります。

この場合、 pathsFromStartToEndallPathsFromStartToEndどちらも2等しくなります。

  const someObject = { propA: true, propB: false };
  const someFunction = (propName) => {
    if (propName === true) {
      console.log("something");
    } else {
      console.log("whatever");
    }
  }
  for (const propName in someObject) {
    someFunction(propName)
  }
  const [myState, setMyState] = useState(null);

理由はまだわかりません。

@gaearon 、この問題に対処して修正するMRを作成しました(#16853)。

これが発生する主な理由は、 allPathsFromStartToEnd値が正しく計算されていないことです。
この例では、開始から終了までのパスの数は3である必要がありますが、関数は2を返します。

これが発生する理由は、循環パスのキャッシュに欠陥があるためです。 したがって、通常のグラフトラバースでは、パス履歴も必要ですが、循環要素のリストのみが必要であり、このパスにつながる要素は不明です。
その結果、条件がfor...in objで使用される場合、方向に基づいて、いくつかのパスが失われる可能性があります。

これは2.4.0の問題であり、少し単純な再現です。

import * as React from "react";

function Component() {
  let isLastEven = false;
  for (let x of [1, 2, 3]) {
    if (x % 2 == 0) {
      isLastEven = true;
    } else {
      isLastEven = false;
    }
  }
  let y = React.useMemo(() => 1, []);
  return <div>{y}</div>;
}

#16853を再開できますか?

このページは役に立ちましたか?
0 / 5 - 0 評価