1. ホーム
  2. javascript

[解決済み] [Solved] Uncaught Invariant Violation: 前のレンダリング中よりも多くのフックをレンダリングする

2022-02-07 18:35:17

質問

次のようなコンポーネントがあります(非常に単純化されたバージョン)。

const component = (props: PropTypes) => {

    const [allResultsVisible, setAllResultsVisible] = useState(false);

    const renderResults = () => {
        return (
            <section>
                <p onClick={ setAllResultsVisible(!allResultsVisible) }>
                    More results v
                </p>
                {
                    allResultsVisible &&
                        <section className="entity-block--hidden-results">
                            ...
                        </section>
                }
            </section>
        );
    };

    return <div>{ renderResults() }</div>;
}

このコンポーネントが使用されているページを読み込むと、このようなエラーが発生します。 Uncaught Invariant Violation: Rendered more hooks than during the previous render. このエラーの説明を探したのですが、検索しても結果が出ません。

コンポーネントを少し修正した場合。

const component = (props: PropTypes) => {

    const [allResultsVisible, setAllResultsVisible] = useState(false);

    const handleToggle = () => {
        setAllResultsVisible(!allResultsVisible);
    }

    const renderResults = () => {
        return (
            <section>
                <p onClick={ handleToggle }>
                    More results v
                </p>
                {
                    allResultsVisible &&
                        <section className="entity-block--hidden-results">
                            ...
                        </section>
                }
            </section>
        );
    };

    return <div>{ renderResults() }</div>;
}

そのエラーは出なくなりました。それは、私が setState が返す jsx 内の関数です。 renderResults ? なぜこの修正が効くのか、説明があるとうれしいです。

解決方法は?

この修正は、最初のコードサンプル(エラーのあるもの)が onClick 一方、2番目(正常に動作するもの)は、関数を onClick . この違いは、JavaScriptでは「このコードを実行する」という意味を持つ、重要な括弧の違いです。

最初のサンプルコードでは、毎回 component がレンダリングされます。 renderResults が呼び出されます。そのたびに setAllResultsVisible(!allResultsVisible) が、クリックを待つのではなく、呼び出されます。Reactは独自のスケジュールでレンダーを実行するため、これが何回起こるかわかりません。

Reactのドキュメントより。

JSXでは、イベントハンドラとして、文字列ではなく、関数を渡します。

Reactのイベント処理に関するドキュメント

注:最初のコードサンプルをサンドボックスで実行しても、この正確なエラーメッセージを得ることはできませんでした。私のエラーは、無限ループを指していました。もしかしたら、より新しいバージョンのReactでは、このようなエラーが発生するのかもしれません。