キャッチされない不変違反: 前回のレンダリング時よりも多くのフックがレンダリングされました 質問する

キャッチされない不変違反: 前回のレンダリング時よりも多くのフックがレンダリングされました 質問する

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

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? 修正が機能する理由の説明があるとありがたいです。

ベストアンサー1

私も同じ問題に直面しました。私がやっていたことは次のようなものでした:

const Table = (listings) => {

    const {isLoading} = useSelector(state => state.tableReducer);

    if(isLoading){
        return <h1>Loading...</h1>
    }

    useEffect(() => {
       console.log("Run something")
    }, [])

    return (<table>{listings}</table>)
}

最初のレンダリングでコンポーネントが早く返され、useEffect が実行されなかったのが原因だと思います。isLoading 状態が変化すると、useEffect が実行され、フックが前回のレンダリングよりも多くレンダリングされたというエラーが発生しました。

簡単な変更で修正できました:

const Table = (listings) => {
    
    const {isLoading} = useSelector(state => state.tableReducer);
        
    useEffect(() => {
        console.log("Run something")
    }, [])
    
    if(isLoading){
        return <h1>Loading...</h1>
    }
    return (<table>{listings}</table>)
}

おすすめ記事